渐变面板中的闪烁

发布于 2024-12-01 17:03:27 字数 179 浏览 1 评论 0原文

我从 TPanel 继承了一个控件,并在 Paint 事件处理程序中,我使用渐变绘制了整个客户端矩形。在用户调整大小之前,这工作得很好。 调整面板大小时,面板组件闪烁过多。

我怎样才能避免这种闪烁。我在MS Office 2007中看到了渐变,即使我们调整客户区的大小,也不会出现闪烁。请赐教我这一点。

感谢期待

I have inherited a control from TPanel and in the Paint event handler, I have drawn the entire client rect using a gradient. This works perfectly fine until the user resizes.
When the panel is resized, the panel component flickers too much.

How can i avoid this flicker. I saw the gradients in MS office 2007, even if we resize the client area, there will not be a flicker. Please enlighten me on this.

Thanks in anticipation

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

幼儿园老大 2024-12-08 17:03:27

您可能想看看这个问题如何消除 TPaintBox 右边缘的闪烁(例如调整大小时)

很好地概述了避免闪烁以及 TPanel 的选项。

编辑 :
我在 Windows 7 上的 Delphi XE 版本中进行了快速测试。

使用此代码我无法重现任何闪烁。
继承的 Paint 被删除,Paint 例程相当快。

如果您仍然可以看到闪烁,则可以实施 Simon 的建议,但最好保留为组件本身的生命周期创建的位图。

unit MainForm;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls;

type
  TGradientPanel = class(TPanel)
  protected
    procedure Paint; override;
  public
    constructor Create(AOwner: TComponent); override;
  end;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
    sPanel : TGradientPanel;
  public
    { Public declarations }
 end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

Uses Math;

 procedure GradVertical(Canvas:TCanvas; Rect:TRect; FromColor, ToColor:TColor) ;
 var
   Y:integer;
   dr,dg,db:Extended;
   C1,C2:TColor;
   r1,r2,g1,g2,b1,b2:Byte;
   R,G,B:Byte;
   cnt:Integer;
 begin
    C1 := FromColor;
    R1 := GetRValue(C1) ;
    G1 := GetGValue(C1) ;
    B1 := GetBValue(C1) ;

    C2 := ToColor;
    R2 := GetRValue(C2) ;
    G2 := GetGValue(C2) ;
    B2 := GetBValue(C2) ;

    dr := (R2-R1) / Rect.Bottom-Rect.Top;
    dg := (G2-G1) / Rect.Bottom-Rect.Top;
    db := (B2-B1) / Rect.Bottom-Rect.Top;

    cnt := 0;
    for Y := Rect.Top to Rect.Bottom-1 do
    begin
       R := R1+Ceil(dr*cnt) ;
       G := G1+Ceil(dg*cnt) ;
       B := B1+Ceil(db*cnt) ;

       Canvas.Pen.Color := RGB(R,G,B) ;
       Canvas.MoveTo(Rect.Left,Y) ;
       Canvas.LineTo(Rect.Right,Y) ;
       Inc(cnt) ;
    end;
 end;


constructor TGradientPanel.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  Self.ParentBackground := FALSE;
end;

procedure TGradientPanel.Paint;
var
  rect : TRect;
begin
  //inherited;  // Avoid any inherited paint actions as they may clear the panel background
  rect := GetClientRect;
  GradVertical( Self.Canvas, rect, clBlue, clRed);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  sPanel := TGradientPanel.Create( Self);
  sPanel.Parent := Self;
  sPanel.Top := 10;
  sPanel.Left := 10;
  sPanel.Width := 300;
  sPanel.Height := 300;
  sPanel.Anchors := [akLeft,akRight,akTop,akBottom];
  sPanel.Enabled := TRUE;
  sPanel.Visible := TRUE;
end;

end.

You may want to look at this question How to eliminate the flicker on the right edge of TPaintBox (for example when resizing)

Good overview of options to avoid flicker and also for TPanel.

Edit :
I made a quick test in my Delphi XE version on windows 7.

With this code I cannot reproduce any flicker.
The inherited Paint is removed and the Paint routine is quite fast.

If you still can see flicker, the proposal from Simon can be implemented, but better keep the bitmap created for the lifetime of the component itself.

unit MainForm;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls;

type
  TGradientPanel = class(TPanel)
  protected
    procedure Paint; override;
  public
    constructor Create(AOwner: TComponent); override;
  end;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
    sPanel : TGradientPanel;
  public
    { Public declarations }
 end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

Uses Math;

 procedure GradVertical(Canvas:TCanvas; Rect:TRect; FromColor, ToColor:TColor) ;
 var
   Y:integer;
   dr,dg,db:Extended;
   C1,C2:TColor;
   r1,r2,g1,g2,b1,b2:Byte;
   R,G,B:Byte;
   cnt:Integer;
 begin
    C1 := FromColor;
    R1 := GetRValue(C1) ;
    G1 := GetGValue(C1) ;
    B1 := GetBValue(C1) ;

    C2 := ToColor;
    R2 := GetRValue(C2) ;
    G2 := GetGValue(C2) ;
    B2 := GetBValue(C2) ;

    dr := (R2-R1) / Rect.Bottom-Rect.Top;
    dg := (G2-G1) / Rect.Bottom-Rect.Top;
    db := (B2-B1) / Rect.Bottom-Rect.Top;

    cnt := 0;
    for Y := Rect.Top to Rect.Bottom-1 do
    begin
       R := R1+Ceil(dr*cnt) ;
       G := G1+Ceil(dg*cnt) ;
       B := B1+Ceil(db*cnt) ;

       Canvas.Pen.Color := RGB(R,G,B) ;
       Canvas.MoveTo(Rect.Left,Y) ;
       Canvas.LineTo(Rect.Right,Y) ;
       Inc(cnt) ;
    end;
 end;


constructor TGradientPanel.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  Self.ParentBackground := FALSE;
end;

procedure TGradientPanel.Paint;
var
  rect : TRect;
begin
  //inherited;  // Avoid any inherited paint actions as they may clear the panel background
  rect := GetClientRect;
  GradVertical( Self.Canvas, rect, clBlue, clRed);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  sPanel := TGradientPanel.Create( Self);
  sPanel.Parent := Self;
  sPanel.Top := 10;
  sPanel.Left := 10;
  sPanel.Width := 300;
  sPanel.Height := 300;
  sPanel.Anchors := [akLeft,akRight,akTop,akBottom];
  sPanel.Enabled := TRUE;
  sPanel.Visible := TRUE;
end;

end.
锦欢 2024-12-08 17:03:27

减少闪烁的一种方法是将渐变绘制到临时位图,然后将位图的全部内容绘制到面板。此方法假设您有一个 OnPaint 方法和一个可以在继承的面板中绘制的画布。

所以像这样(未经测试)

var bmp : Tbitmap;

procedure AfterConstruction;
begin
  bmp := TBitmap.Create;
end;

procedure Destroy()
begin
  if Assigned(bmp) then FreeandNil(bmp);
end;

//redraw you bmp gradient
procedure Panel1.OnResize();
begin
  if Assigned(bmp) then //ensure the bmp s created in your constructor
  begin
  try
    bmp.SetBounds(Panel1.Clientrect); //ensure the bmp is the same size as the panel
    //draw your gradient on the bmp
    Panel1.OnPaint();//repaint the tpanel

  finally
    bmp.Free;
  end;
end;

//paint to the panel
procedure Panel1.OnPaint()
begin
  Panel1.Canvas.Draw(0,0,bmp); //use the OnPaint method to draw to the canvas
end;
  end;
end;

A way to reduce flicker is to draw the gradient to a temporary bitmap the draw the entire contents of the bitmap to the panel. This method assumes you have an OnPaint method and a canvas to draw on in your inherited panel.

So something like this (untested)

var bmp : Tbitmap;

procedure AfterConstruction;
begin
  bmp := TBitmap.Create;
end;

procedure Destroy()
begin
  if Assigned(bmp) then FreeandNil(bmp);
end;

//redraw you bmp gradient
procedure Panel1.OnResize();
begin
  if Assigned(bmp) then //ensure the bmp s created in your constructor
  begin
  try
    bmp.SetBounds(Panel1.Clientrect); //ensure the bmp is the same size as the panel
    //draw your gradient on the bmp
    Panel1.OnPaint();//repaint the tpanel

  finally
    bmp.Free;
  end;
end;

//paint to the panel
procedure Panel1.OnPaint()
begin
  Panel1.Canvas.Draw(0,0,bmp); //use the OnPaint method to draw to the canvas
end;
  end;
end;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文