Recent

Author Topic: Draw on control outside paintevent  (Read 5311 times)

zamtmn

  • Sr. Member
  • ****
  • Posts: 365
Draw on control outside paintevent
« on: June 28, 2014, 11:50:12 am »
I need draw on TPanel outside paintevent.
In gtk2 and win this work:
Code: [Select]
unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  {$IFDEF LCLQT}
  qtwidgets,qt4,
  {$ENDIF}
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls;

type

  { TForm1 }

  TForm1 = class(TForm)
    Panel1: TPanel;
    procedure _onCreate(Sender: TObject);
    procedure _onMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
  private
    { private declarations }
  public
    { public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }

procedure TForm1._onMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer
  );
begin
     panel1.Canvas.Line(0,0,x,y);
end;

procedure TForm1._onCreate(Sender: TObject);
begin
     {$IFDEF LCLQT}
     TQtWidget(Panel1.Handle).setAttribute(QtWA_PaintOutsidePaintEvent);
     {$ENDIF}
end;

end.
but on qt this not work, although setAttribute(QtWA_PaintOutsidePaintEvent)
Is it possible to achieve such drawing in LCL with qt widgeset?

zeljko

  • Hero Member
  • *****
  • Posts: 1080
    • http://wiki.lazarus.freepascal.org/User:Zeljan
Re: Draw on control outside paintevent
« Reply #1 on: June 28, 2014, 01:26:42 pm »
1.That can work only on linux. Mac and win32 won't work according to the qt documentation.
2.LCL-Qt waits for QPaintEvent from qt and then creates context and everything, so I'm not sure that panel1.Canvas.Line(0,0,x,y); can work just like that.
You shuold check if panel1.Canvas.HandleAllocated and if not then
use LCLIntf.BeginPaint() and LCLIntf.EndPaint() to create context and everything.Maybe then it'll work.

hinst

  • Sr. Member
  • ****
  • Posts: 303
Re: Draw on control outside paintevent
« Reply #2 on: June 28, 2014, 01:46:59 pm »
You don't really need to paint outside paint event. This kind of logic could be easily coded in a way that drawing routine would be called from OnPaint handler. Draw your lines in OnPaint handler and call Invalidate method to make control repaint itself & call your drawing routine. You can use a Timer for this and call Invalidate from OnTimer handler
Too late to escape fate

zamtmn

  • Sr. Member
  • ****
  • Posts: 365
Re: Draw on control outside paintevent
« Reply #3 on: June 28, 2014, 03:07:52 pm »
zeljko
>>use LCLIntf.BeginPaint() and LCLIntf.EndPaint() to create context and everything.Maybe then it'll work.
not work((
Code: [Select]
unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  {$IFDEF LCLQT}
  qtwidgets,qt4,
  {$ENDIF}
  LCLIntf,LCLType,Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls;

type

  { TForm1 }

  TForm1 = class(TForm)
    Panel1: TPanel;
    procedure _onCreate(Sender: TObject);
    procedure _onMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
  private
    { private declarations }
  public
    { public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }

procedure TForm1._onMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer
  );
var
  PaintStruct: TPaintStruct;
begin
     LCLIntf.BeginPaint(panel1.Handle,PaintStruct);
     panel1.Canvas.Line(0,0,x,y);
     LCLIntf.EndPaint(panel1.Handle,PaintStruct);
end;

procedure TForm1._onCreate(Sender: TObject);
begin
     {$IFDEF LCLQT}
     TQtWidget(Panel1.Handle).setAttribute(QtWA_PaintOutsidePaintEvent);
     {$ENDIF}
end;

end.

hinst
No it is only right decision. Invalidate, and especially the timer - will antsy and torn. I need repainting while moving the mouse and not when it stops. Any missed frames worsen behavior

zeljko

  • Hero Member
  • *****
  • Posts: 1080
    • http://wiki.lazarus.freepascal.org/User:Zeljan
Re: Draw on control outside paintevent
« Reply #4 on: June 29, 2014, 09:34:24 am »
zeljko
>>use LCLIntf.BeginPaint() and LCLIntf.EndPaint() to create context and everything.Maybe then it'll work.
not work((
Code: [Select]
unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  {$IFDEF LCLQT}
  qtwidgets,qt4,
  {$ENDIF}
  LCLIntf,LCLType,Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls;

type

  { TForm1 }

  TForm1 = class(TForm)
    Panel1: TPanel;
    procedure _onCreate(Sender: TObject);
    procedure _onMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
  private
    { private declarations }
  public
    { public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }

procedure TForm1._onMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer
  );
var
  PaintStruct: TPaintStruct;
begin
     LCLIntf.BeginPaint(panel1.Handle,PaintStruct);
     panel1.Canvas.Line(0,0,x,y);
     LCLIntf.EndPaint(panel1.Handle,PaintStruct);
end;

procedure TForm1._onCreate(Sender: TObject);
begin
     {$IFDEF LCLQT}
     TQtWidget(Panel1.Handle).setAttribute(QtWA_PaintOutsidePaintEvent);
     {$ENDIF}
end;

end.

You're doing it wrong.
     LCLIntf.BeginPaint(panel1.Handle,PaintStruct);
     panel1.Canvas.Line(0,0,x,y);
     LCLIntf.EndPaint(panel1.Handle,PaintStruct);

Where do you set PaintStruct values ?
See qtwinapi.inc -> BeginPaint() & EndPaint() what is needed to get it work.Also, your panel1.Canvas.Handle should be assigned from LCLIntf.BeginPaint hdc.
1. TQtWidget(Panel1.Handle).PaintData should be filled properly before calling to BeginPaint()
2.Panel1.Canvas.Handle := LCLIntf.BeginPaint().
3.Maybe I can simplify BeginPaint and automatically fill PaintData in this case, but need test project, for now it must be filled like it is in TQtWidget.SlotPaint().



zamtmn

  • Sr. Member
  • ****
  • Posts: 365
Re: Draw on control outside paintevent
« Reply #5 on: June 29, 2014, 06:50:09 pm »
zeljko
Please give an example of filling needed struct based on this:
Code: [Select]
unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  {$IFDEF LCLQT}
  qtwidgets,qt4,
  {$ENDIF}
  LCLIntf,LCLType,Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls;

type

  { TForm1 }

  TForm1 = class(TForm)
    Panel1: TPanel;
    procedure _onCreate(Sender: TObject);
    procedure _onMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
  private
    { private declarations }
  public
    { public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }

procedure TForm1._onMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer
  );
var
  PaintStruct: TPaintStruct;
begin
     LCLIntf.BeginPaint(panel1.Handle,PaintStruct);
     panel1.Canvas.Line(0,0,x,y);
     LCLIntf.EndPaint(panel1.Handle,PaintStruct);
end;

procedure TForm1._onCreate(Sender: TObject);
begin
     {$IFDEF LCLQT}
     TQtWidget(Panel1.Handle).setAttribute(QtWA_PaintOutsidePaintEvent);
     {$ENDIF}
end;

end. 
I can not get it done.