最好的方法做非闪烁,分割图形更新在Delphi?
我想我可以把它抛出来,只是问:我看过德尔福控件在图形效果方面是完美的。含义:没有闪烁,分段更新(只重绘控制的标记为脏的部分)和平滑滚动。
我已经编码了许多图形控制多年,所以我知道双缓冲,dibs,bitblts和所有的“常见”的东西(我总是使用dibs绘制一切,如果可能,但有一个开销)。也知道关于InvalidateRect和检查TCanvas.ClipRect为需要更新的实际rect。尽管所有这些典型的解决方案,我发现很难创建相同的质量组件,如说Developer Express或Razed组件。如果图形是平滑的,你可以下注滚动条(本机)闪烁,如果滚动条和框架是平滑的,你可以在滚动期间发出背景闪烁。 有没有标准的代码设置来处理这个?一种最佳实践,确保整个控制的平滑重绘 – 包括控制的非客户区域? 例如,这里是一个“裸骨”控件,为分段更新(只需要重绘需要的高度)。如果在表单上创建它,请尝试在其上移动窗口,并观察它用颜色替换部件(请参见paint方法)。 有没有人有类似的基类可以处理非客户区重绘,没有闪烁? type TMyControl = Class(TCustomControl) private (* TWinControl: Erase background prior to client-area paint *) procedure WMEraseBkgnd(var Message: TWmEraseBkgnd);message WM_ERASEBKGND; Protected (* TCustomControl: Overrides client-area paint mechanism *) Procedure Paint;Override; (* TWinControl: Adjust Win32 parameters for CreateWindow *) procedure CreateParams(var Params: TCreateParams);override; public Constructor Create(AOwner:TComponent);override; End; { TMyControl } Constructor TMyControl.Create(AOwner:TComponent); Begin inherited Create(Aowner); ControlStyle:=ControlStyle - [csOpaque]; end; procedure TMyControl.CreateParams(var Params: TCreateParams); begin inherited CreateParams(Params); (* When a window has this style set,any areas that its child windows occupy are excluded from the update region. *) params.ExStyle:=params.ExStyle + WS_CLIPCHILDREN; (* Exclude VREDRAW & HREDRAW *) with Params.WindowClass do Begin (* When a window class has either of these two styles set,the window contents will be completely redrawn every time it is resized either vertically or horizontally (or both) *) style:=style - CS_VREDRAW; style:=style - CS_HREDRAW; end; end; procedure TMyControl.Paint; (* Inline proc: check if a rectangle is "empty" *) function isEmptyRect(const aRect:TRect):Boolean; Begin result:=(arect.Right=aRect.Left) and (aRect.Bottom=aRect.Top); end; (* Inline proc: Compare two rectangles *) function isSameRect(const aFirstRect:TRect;const aSecondRect:TRect):Boolean; Begin result:=sysutils.CompareMem(@aFirstRect,@aSecondRect,SizeOf(TRect)) end; (* Inline proc: This fills the background completely *) Procedure FullRepaint; var mRect:TRect; Begin mRect:=getClientRect; AdjustClientRect(mRect); Canvas.Brush.Color:=clWhite; Canvas.Brush.Style:=bsSolid; Canvas.FillRect(mRect); end; begin (* A full redraw is only issed if: 1. the cliprect is empty 2. the cliprect = clientrect *) if isEmptyRect(Canvas.ClipRect) or isSameRect(Canvas.ClipRect,Clientrect) then FullRepaint else Begin (* Randomize a color *) Randomize; Canvas.Brush.Color:=RGB(random(255),random(255),random(255)); (* fill "dirty rectangle" *) Canvas.Brush.Style:=bsSolid; Canvas.FillRect(canvas.ClipRect); end; end; procedure TMyControl.WMEraseBkgnd(var Message: TWmEraseBkgnd); begin message.Result:=-1; end; 更新 我只是想补充说,诀窍是什么组合: > ExcludeClipRect()当绘制非客户端区域,所以你不会重叠的图形在clientarea XEdge := GetSystemMetrics(SM_CXEDGE); YEdge := GetSystemMetrics(SM_CYEDGE); >当你有移动或调整大小的滚动条时,使用以下标志调用RedrawWindow(): mRect:=ClientRect; mFlags:=rdw_Invalidate or RDW_NOERASE or RDW_FRAME or RDW_INTERNALPAINT or RDW_NOCHILDREN; RedrawWindow(windowhandle,@mRect,mFlags); >在Paint()方法中更新背景时,避免绘制可能的子对象,像这样(参见上面提到的RDW_NOCHILDREN): for x := 1 to ControlCount do begin mCtrl:=Controls[x-1]; if mCtrl.Visible then Begin mRect:=mCtrl.BoundsRect; ExcludeClipRect(Canvas.Handle,mRect.Left,mRect.Top,mRect.Right,mRect.Bottom); end; end; 感谢帮助家伙! 解决方法
嗯,你的TMyControl没有非客户区(尚)。所以我添加BorderWidth:= 10;现在它有。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |