Monday, 26 November 2012

How to draw a gradient background

My previous post I wrote about how to reduce flicker on a gradient background and did not mention how to create a gradient background. Here is how I create a gradient background.

Interface

procedure GradVertical(Canvas: TCanvas; Rect: TRect; FromColor, ToColor: TColor);

Implemention


procedure TForm1.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;


procedure TForm1.ButtonClick(Sender: TObject);
var
    Rect: TRect;
begin
    Rect := GetClientRect;
    GradVertical(Self.Canvas, Rect, clBlack, clRed);
end;

Thursday, 22 November 2012

Screen flicker with gradient background

Recently I had a problem with flickering when resizing a screen due to a gradient background. The problem was mainly noticeable with control on top of the background. Below are a couple of snippets that might help.

First I tried this:

// Interface
procedure WMEraseBackground(var _message:TMessage); message WM_ERASEBKGND;

// Implementation
procedure TForm.WMEraseBackground(var _message: TMessage);
begin
    _message.Result := 1;
end;

This helped with the flicker on the gradient panel, but I noticed other issues with some other controls not painting correctly and a panel having a thicker border. Then I tried this:

// Interface
procedure WMEnterSizeMove(var Message:TWMMove); message WM_ENTERSIZEMOVE;
procedure WMExitSizeMove(var Message:TWMMove); message WM_EXITSIZEMOVE;

procedure TfrmMain.WMEnterSizeMove(var Message: TWMMove);
begin
    // Set controls to visible = false
end;

procedure TfrmMain.WMExitSizeMove(var Message: TWMMove);
begin
    // Set controls to visible = true
end;

Doing this really helped the other controls from flicking, when the user resizes the window the controls disappear and then reappear once the resize is complete. 

Tuesday, 6 November 2012

Prevent screen refresh and flickering

To prevent screen refresh and flickering in an application it is often useful to lock the screen. This can occur with data aware controls which involve iteration and can make the application look strange to the user. I have found 2 solutions to this problem, the first is the one I use most of the time, but the second also works well. 

Solution 1


LockWindowUpdate(Handle);
try
    // Code goes here
finally
    LockWindowUpdate(0);
end;

Solution 2


SendMessage(Handle, WM_SETREDRAW, WPARAM(False), 0);
try
     // Code goes here
finally
    SendMessage(Handle, WM_SETREDRAW, WPARAM(True), 0);
    RedrawWindow(Self.Handle, nil, 0, RDW_ERASE or RDW_FRAME or RDW_INVALIDATE or RDW_ALLCHILDREN);
end;

These 2 solutions help with screen refresh, however there are other instances when these do not work, for example when using a gradient background.