Recent

Author Topic: [SOLVED] How does InvalidateRect procedure work?  (Read 10841 times)

Awesome Programmer

  • Sr. Member
  • ****
  • Posts: 479
  • Programming is FUN only when it works :)
    • Cool Technology
[SOLVED] How does InvalidateRect procedure work?
« on: June 11, 2013, 06:28:49 pm »
I am working on a program much like the MSPaint program using Lazarus. However, I am running into a problem. Every time I try to invalidate a section of a form using
Code: [Select]
InvalidateRect(MyForm.Handle,@bounds, false) after a change has been made, it won't invalidate or refresh that part of the form. However, if I invalidate the whole form using
Code: [Select]
MyForm.Invalidate within formpaint event, it works but it is always invalidating that my program kind of get stuck when you try to do anything else like open dialog box.

So, how does InvalidateRect procedure works? How do you use it?
« Last Edit: June 12, 2013, 07:40:18 pm by reltek »

zeljko

  • Hero Member
  • *****
  • Posts: 1949
    • http://wiki.lazarus.freepascal.org/User:Zeljan
Re: How does InvalidateRect procedure work?
« Reply #1 on: June 11, 2013, 06:47:12 pm »
What widgetset ? Have you tried InvalidateRect(MyForm.Handle,@Bounds, True{this should erase background}) ?

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: How does InvalidateRect procedure work?
« Reply #2 on: June 11, 2013, 07:11:03 pm »
Invalidate forces a repaint for a window (windows OS) you do not use it inside a ONPaint event because it creates a loop making it hard for everything else to execute.

Invalidate is used for example when you change a property (eg background color) and you want the control to repaint it self.
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

Awesome Programmer

  • Sr. Member
  • ****
  • Posts: 479
  • Programming is FUN only when it works :)
    • Cool Technology
Re: How does InvalidateRect procedure work?
« Reply #3 on: June 11, 2013, 07:56:59 pm »
What widgetset ? Have you tried InvalidateRect(MyForm.Handle,@Bounds, True{this should erase background}) ?

I just did and it didn't do much difference. It is acting the same way.
« Last Edit: June 11, 2013, 08:31:52 pm by reltek »

Blaazen

  • Hero Member
  • *****
  • Posts: 3241
  • POKE 54296,15
    • Eye-Candy Controls
Re: How does InvalidateRect procedure work?
« Reply #4 on: June 11, 2013, 10:14:07 pm »
Here you have a little demo. Like mentioned above - you should never call Invalidate from within Paint method. Some widgetsets don't like - especially GTK2. Just put two buttons on the form and assign onclick events.

Code: [Select]
unit Unit1;
{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, LCLIntf;

type
  { TForm1 }
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure FormPaint(Sender: TObject);
  private
    { private declarations }
    InvRectOnly: Boolean;
    InvRect: TRect;
  public
    { public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }

procedure TForm1.Button1Click(Sender: TObject);
begin
  InvRectOnly := True;
  InvRect := Rect(20, 20, 100, 100);
  InvalidateRect(self.Handle, @InvRect, True);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  InvRectOnly := False;
  Invalidate;
end;

procedure TForm1.FormPaint(Sender: TObject);
begin
  if not InvRectOnly
    then Canvas.GradientFill(Rect(0, 0, Width, Height), clRed, clBlue, gdHorizontal)
    else begin
      Canvas.Brush.Color := clGreen;
      Canvas.FillRect(InvRect);
    end;
  InvRectOnly := False;
end;

end.
Lazarus 2.3.0 (rev main-2_3-2863...) FPC 3.3.1 x86_64-linux-qt Chakra, Qt 4.8.7/5.13.2, Plasma 5.17.3
Lazarus 1.8.2 r57369 FPC 3.0.4 i386-win32-win32/win64 Wine 3.21

Try Eye-Candy Controls: https://sourceforge.net/projects/eccontrols/files/

Awesome Programmer

  • Sr. Member
  • ****
  • Posts: 479
  • Programming is FUN only when it works :)
    • Cool Technology
Re: How does InvalidateRect procedure work?
« Reply #5 on: June 12, 2013, 04:43:36 pm »
Here you have a little demo. Like mentioned above - you should never call Invalidate from within Paint method. Some widgetsets don't like - especially GTK2. Just put two buttons on the form and assign onclick events.

Code: [Select]
unit Unit1;
{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, LCLIntf;

type
  { TForm1 }
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure FormPaint(Sender: TObject);
  private
    { private declarations }
    InvRectOnly: Boolean;
    InvRect: TRect;
  public
    { public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }

procedure TForm1.Button1Click(Sender: TObject);
begin
  InvRectOnly := True;
  InvRect := Rect(20, 20, 100, 100);
  InvalidateRect(self.Handle, @InvRect, True);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  InvRectOnly := False;
  Invalidate;
end;

procedure TForm1.FormPaint(Sender: TObject);
begin
  if not InvRectOnly
    then Canvas.GradientFill(Rect(0, 0, Width, Height), clRed, clBlue, gdHorizontal)
    else begin
      Canvas.Brush.Color := clGreen;
      Canvas.FillRect(InvRect);
    end;
  InvRectOnly := False;
end;

end.

Fantastic Blaazen. I love your example. I did setup the project and was able to compile the program successfully. When I click button1, I get a green square up in the corner of the form. When I click button2, the green square goes away. I guess that's because you are updating the whole form with gradient color and invalidating it.

So, okay now. my problem is this. After you click button1, you get the green square. Then, you take a window or another program's GUI and just drag it over the green square. When  you do, you should notice that the green square is erased and goes away. I don't want that. I want the green square to be displayed whether some other window hides or not. How do you keep it from being erased by other window(s)?

Blaazen

  • Hero Member
  • *****
  • Posts: 3241
  • POKE 54296,15
    • Eye-Candy Controls
Re: How does InvalidateRect procedure work?
« Reply #6 on: June 12, 2013, 05:17:43 pm »
Form.Canvas will display only what you paint there. "Invalidate" comes very often. When Form obtains or looses focus or when you drag something over. From this point of view, Form.Canvas is volatile. InvalidateRect is kind of optimalization because sometimes you don't need to repaint everything. But many times you need to do so.
If you need the green rectangle always, you can:
- Paint it always
or
- use some buffered component (TImage)
Lazarus 2.3.0 (rev main-2_3-2863...) FPC 3.3.1 x86_64-linux-qt Chakra, Qt 4.8.7/5.13.2, Plasma 5.17.3
Lazarus 1.8.2 r57369 FPC 3.0.4 i386-win32-win32/win64 Wine 3.21

Try Eye-Candy Controls: https://sourceforge.net/projects/eccontrols/files/

Awesome Programmer

  • Sr. Member
  • ****
  • Posts: 479
  • Programming is FUN only when it works :)
    • Cool Technology
Re: How does InvalidateRect procedure work?
« Reply #7 on: June 12, 2013, 07:40:03 pm »
Thanks for your help, Blaazen. I solved my programming issue.

I used Bitmap for Image. My formpaint event as follows which works as expected without any issue.

Code: [Select]
procedure TviewFrm.FormPaint(Sender: TObject);
var
  DC,MemDC:HDC;
  MemBitmap,OldBitmap:HBITMAP;
begin
     DC := Canvas.Handle;
     MemBitmap := CreateCompatibleBitmap(DC,ClientRect.Right,ClientRect.Bottom);
     MemDC := CreateCompatibleDC(0);
     OldBitmap := SelectObject(MemDC,MemBitmap);
     Canvas.Handle := MemDC;
     try
        Canvas.Brush.Color := Color;
        Canvas.FillRect(Rect(0,0,ClientWidth,ClientHeight));
        myObjects.Draw;
        BitBlt(DC,0,0,ClientRect.Right,ClientRect.Bottom,MemDC,0,0,SRCCOPY);
     finally
            Canvas.Handle := DC;
            SelectObject(MemDC,OldBitmap);
            DeleteDC(MemDC);
            DeleteObject(MemBitmap);
     end;
end;

Thanks for your help again.
« Last Edit: June 12, 2013, 07:44:32 pm by reltek »

 

TinyPortal © 2005-2018