最好的方法做非闪烁,分割图形更新在Delphi?

前端之家收集整理的这篇文章主要介绍了最好的方法做非闪烁,分割图形更新在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
>捕获WMNCCalcSize消息,而不仅仅是使用borderize进行测量。我也不得不采取高度的边缘大小:

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;

感谢帮助家伙!

解决方法

For instance,here is a “bare bone” control which take height for segmented updates (only redraw what is needed). If you create it on a form,try moving a window over it,and watch it replace the parts with colors (see paint method).

Does anyone have a similar base class that can handle non client area redraws without flickering?

嗯,你的TMyControl没有非客户区(尚)。所以我添加BorderWidth:= 10;现在它有。

猜你在找的Delphi相关文章