Recent

Author Topic: flickering main window  (Read 12335 times)

Hansvb

  • Hero Member
  • *****
  • Posts: 602
flickering main window
« on: October 25, 2014, 10:57:56 pm »
In the onpaint method of my main form i redraw a panel. It gets a gradient color.
The panel flickers when the form is being resized. And even on a mouse movement. Is there something like double buffering like delphi to avoid the flickering panel?

lainz

  • Hero Member
  • *****
  • Posts: 4460
    • https://lainz.github.io/
Re: flickering main window
« Reply #1 on: October 25, 2014, 11:09:10 pm »
Self.DoubleBuffered := True;

Panel1.DoubleBuffered := True;

Hansvb

  • Hero Member
  • *****
  • Posts: 602
Re: flickering main window
« Reply #2 on: October 25, 2014, 11:17:53 pm »
Thanks, but where to put that code? When i put in on the onpaint method of the main window or in the on resize of the panel, the panel stil flickers.

User137

  • Hero Member
  • *****
  • Posts: 1791
    • Nxpascal home
Re: flickering main window
« Reply #3 on: October 26, 2014, 01:05:56 am »
Put in the onFormCreate event.

Hansvb

  • Hero Member
  • *****
  • Posts: 602
Re: flickering main window
« Reply #4 on: October 27, 2014, 08:18:35 pm »
Double buffers is not the answer for the flickering. Ik think i leave the gradient color or go back to the bgra controls.

wp

  • Hero Member
  • *****
  • Posts: 11858
Re: flickering main window
« Reply #5 on: October 27, 2014, 09:11:44 pm »
How do you paint the gradient?

Hansvb

  • Hero Member
  • *****
  • Posts: 602
Re: flickering main window
« Reply #6 on: October 27, 2014, 09:17:46 pm »
The gradient is made with:

Code: [Select]
procedure TVisueel.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; 

wp

  • Hero Member
  • *****
  • Posts: 11858
Re: flickering main window
« Reply #7 on: October 27, 2014, 09:37:18 pm »
Could you try the gradient procedure of spkToolbar? This is a package where people were complaining initially about its slow speed, but it is much faster now. The main gradient of the toolbar is painted by the GradientFill method of the canvas and, what seems to be more important to me, goes into a temporary bitmap first which seems to be more efficient than the DoubleBuffered mechanism.

You can find spkToolbar in ccr. The gradient painting is in spkGraphTools.


taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: flickering main window
« Reply #8 on: October 27, 2014, 09:54:31 pm »
Could you try the gradient procedure of spkToolbar? This is a package where people were complaining initially about its slow speed, but it is much faster now. The main gradient of the toolbar is painted by the GradientFill method of the canvas and, what seems to be more important to me, goes into a temporary bitmap first which seems to be more efficient than the DoubleBuffered mechanism.

You can find spkToolbar in ccr. The gradient painting is in spkGraphTools.

Well the double buffer mechanism should be just that a bitmap that all draw goes to and when finished it is transfered on screen. What you propose is at least questionable (doubling the double buffer) creating a chain effect loosing speed instead of gaining in the end. That is why delphi (in all its "wisdom") when you set the doublebuffered to true it will make sure that only one bitmap is created for all the parenting chain of components.
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

wp

  • Hero Member
  • *****
  • Posts: 11858
Re: flickering main window
« Reply #9 on: October 27, 2014, 10:24:50 pm »
Taazz, I did not propose a double-double buffering, just a single bitmap buffer, but your arguments are reasonable.

Another idea: In the first posting it is mentioned that the component inherits from TPanel. Doesn't TPanel always erase the background? In this case every redraw induced, for example, by a movement of the mouse will erase the background and repaint it with the gradient - this is flicker. I saw this behavior in a recently fixed issue of spktoolbar (# 0025047) which was resolved by overriding the method EraseBackground with an empty procedure.

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: flickering main window
« Reply #10 on: October 27, 2014, 10:46:12 pm »
Taazz, I did not propose a double-double buffering, just a single bitmap buffer, but your arguments are reasonable.

Another idea: In the first posting it is mentioned that the component inherits from TPanel. Doesn't TPanel always erase the background?

True by overriding the erasebackground (or what ever its name is) and draw the gradient there should keep things a bit cleaner, although this is a bigger problem in lcl, last time I checked there was a black background enforced before the developer got any chance of drawing. I do not know if it has been corrected in the mean time but as far as I understand, it was designed this way.
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

howardpc

  • Hero Member
  • *****
  • Posts: 4144
Re: flickering main window
« Reply #11 on: October 27, 2014, 11:19:48 pm »
TCanvas has a built-in GradientFill() procedure.
You could see if using TVisueel.Canvas.GradientFill() as your gradient routine avoids flicker.

wp

  • Hero Member
  • *****
  • Posts: 11858
Re: flickering main window
« Reply #12 on: October 28, 2014, 12:16:17 am »
Taazz: right again - there is an ugly black area at the right/bottom if EraseBackground is overridden by an empty method and a client-aligned gradient panel is resized. There almost no flicker on my system (Win7, i5), though, if the EraseBackground is not used. No difference between the OP's gradient painting and the canvas' GradientFill. But I don't see any flicker if the gradient panel is double-buffered.

This is my code (just an empty form) which does not cause flicker on my system (other variants commented):
Code: [Select]
unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls, LCLType;

type

  TGradientPanel = class(TPanel)
  protected
    //procedure EraseBackground(DC: HDC); override;
  public
    FromColor, ToColor: TColor;
    procedure Paint; override;
  end;

  { TForm1 }

  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { private declarations }
    gradientPanel: TGradientPanel;
  public
    { public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

uses
  LclIntf, Math;

{ TForm1 }

procedure TForm1.FormCreate(Sender: TObject);
begin
  gradientPanel := TGradientPanel.create(self);
  gradientPanel.Parent := self;
  gradientPanel.Align := alClient;
  gradientPanel.FromColor := clWhite;
  gradientPanel.ToColor := clMoneyGreen;
  gradientPanel.DoubleBuffered := true;
end;

procedure TGradientPanel.Paint;
var
  R: TRect;
begin
  R := Rect(0, 0, Width-1, Height-1);
  Canvas.GradientFill(R, FromColor, ToColor, gdVertical);
end;

                           (*  // OP's painting method
procedure TGradientPanel.Paint;
var
  Y:integer;
  dr,dg,db:Extended;
  C1,C2:TColor;
  r1,r2,g1,g2,b1,b2:Byte;
  R,G,B:Byte;
  cnt:integer;
  rct: TRect;
begin
  rct := Rect(0, 0, Width-1, Height-1);

  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) / rct.Bottom-rct.Top;
  dg := (G2-G1) / rct.Bottom-rct.Top;
  db := (B2-B1) / rct.Bottom-rct.Top;
  cnt := 0;
  for Y := rct.Top to rct.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(rct.Left,Y);
      Canvas.LineTo(rct.Right,Y);
      inc(cnt) ;
    end;
end;
        *)

(*
// black areas if this procedure is present, but no flicker. Occasional flicker of "large" gradient
// if this method is commented.
procedure TGradientPanel.EraseBackground(DC: HDC);
begin
  //
end;
*)
end.
« Last Edit: October 28, 2014, 12:22:09 am by wp »

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: flickering main window
« Reply #13 on: October 28, 2014, 02:46:26 am »
Taazz: right again - there is an ugly black area at the right/bottom if EraseBackground is overridden by an empty method and a client-aligned gradient panel is resized. There almost no flicker on my system (Win7, i5), though, if the EraseBackground is not used. No difference between the OP's gradient painting and the canvas' GradientFill. But I don't see any flicker if the gradient panel is double-buffered.

There are 2 main concerns here (personal opinion warning lights should be going on/off at this point).
1) i5 and almost no flicker shows a very limited threshold for error/experiment and that makes developing unpleasant.
2) The library has a design flaw. There should be no code that can not be replaced at any point at any order. This is a must because a library is not an end user product that is a closed environment, it is an open environment with multiple input sources.

Now to the point, have you tried to place the gradient code inside the erasebackground method instead of leaving it empty? It might have better results.
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: flickering main window
« Reply #14 on: October 28, 2014, 05:48:16 am »
In the onpaint method of my main form i redraw a panel.
This sounds wrong to me. Using the canvas of the panel in the form's OnPaint event is a sure way to get flickering effect. Use the panel's OnPaint event instead. It is not published, but you can assign an event to it and use double buffered canvas. An alternative is to do as wp did above.

 

TinyPortal © 2005-2018