Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / lazarus / 2016-10

Calling DrawFocusRect() outside the Paint() event

18 messages · 6 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Graeme Geldenhuys

Hi,

Working on a visual report designer for the upcoming fpReport. We use Canvas.DrawFocusRect() to draw a selection rectangle around a reporting element (eg: a memo). We can drag that rectangle around in the report designer (which itself is a custom widget). We call the Canvas.DrawFocusRect() from within the MouseMove event. It seems to work fine under LCL-GTK2, but could this be problematic on other platforms, as painting outside the Paint event can normally have undefined results.

Or has LCL somehow resolved the issues of painting outside the Paint event?

On a side note:
The Paint() event for the report designer can potentially have very lengthy code, so we definitely don't want to repaint everything simply because we are dragging a focus rectangle around on the canvas. So if we must, we can obviously work around this by using various states in the Paint method.

Regards,
Graeme

fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal http://fpgui.sourceforge.net/ My public PGP key: http://tinyurl.com/graeme-pgp

Reply by email

Mattias Gaertner
to Graeme Geldenhuys
Show quoted text 9 lines
Hi, Working on a visual report designer for the upcoming fpReport. We use Canvas.DrawFocusRect() to draw a selection rectangle around a reporting element (eg: a memo). We can drag that rectangle around in the report designer (which itself is a custom widget). We call the Canvas.DrawFocusRect() from within the MouseMove event. It seems to work fine under LCL-GTK2, but could this be problematic on other platforms, as painting outside the Paint event can normally have undefined results.

Some widgetsets like Carbon can only paint during the Paint event.

Or has LCL somehow resolved the issues of painting outside the Paint event?

No.
If you want to optimize for mini changes like the focusrect you might want to use a bitmap.

Show quoted text 6 lines
On a side note: The Paint() event for the report designer can potentially have very lengthy code, so we definitely don't want to repaint everything simply because we are dragging a focus rectangle around on the canvas. So if we must, we can obviously work around this by using various states in the Paint method.

You need to optimize the Paint event anyway.
You don't need to draw everything when using InvalidateRect instead of Control.Invalidate.
And in Paint use Canvas.GetClipRect or lclintf's GetClipRGN to avoid unnecessary calculations.

Mattias

Reply by email

Michael Van Canneyt
to Mattias Gaertner
Mattias Gaertner wrote 21 lines
On Mon, 10 Oct 2016 10:21:48 +0100 Graeme Geldenhuys via Lazarus wrote: > Hi, > > Working on a visual report designer for the upcoming fpReport. We use > Canvas.DrawFocusRect() to draw a selection rectangle around a reporting > element (eg: a memo). We can drag that rectangle around in the report > designer (which itself is a custom widget). We call the > Canvas.DrawFocusRect() from within the MouseMove event. It seems to work > fine under LCL-GTK2, but could this be problematic on other platforms, > as painting outside the Paint event can normally have undefined results. Some widgetsets like Carbon can only paint during the Paint event. > Or has LCL somehow resolved the issues of painting outside the Paint event? No. If you want to optimize for mini changes like the focusrect you might want to use a bitmap.

Please explain ?

Show quoted text 13 lines
> On a side note: > The Paint() event for the report designer can potentially have very > lengthy code, so we definitely don't want to repaint everything simply > because we are dragging a focus rectangle around on the canvas. So if we > must, we can obviously work around this by using various states in the > Paint method. You need to optimize the Paint event anyway. You don't need to draw everything when using InvalidateRect instead of Control.Invalidate. And in Paint use Canvas.GetClipRect or lclintf's GetClipRGN to avoid unnecessary calculations.

So, if I understand you correctly, when I want to draw a focus rect, I must (roughly):
- calculate the focusrect,
- Call canvas.invalidaterect() with the focusrect
- in the paint event, check ClipRect (which should equal the focusrect)
- and redraw anything that intersects with the cliprect ?

Correct ?

Michael.

Reply by email

Mattias Gaertner
to Michael Van Canneyt: Please explain ? So, if I understand you correctly, when I want to draw a focus rect, I…
Show quoted text 5 lines
[...] > If you want to optimize for mini changes like the focusrect you might > want to use a bitmap. Please explain ?

Draw to a bitmap and in OnPaint draw that. Similar to a TImage. Then you can also use aggpas.

Show quoted text 9 lines
[...] So, if I understand you correctly, when I want to draw a focus rect, I must (roughly): - calculate the focusrect, - Call canvas.invalidaterect() with the focusrect - in the paint event, check ClipRect (which should equal the focusrect) - and redraw anything that intersects with the cliprect ? Correct ?

Correct.

Mattias

Reply by email

Michael Van Canneyt
to Mattias Gaertner
Mattias Gaertner wrote 11 lines
On Mon, 10 Oct 2016 12:05:41 +0200 (CEST) Michael Van Canneyt via Lazarus wrote: > [...] > > If you want to optimize for mini changes like the focusrect you might > > want to use a bitmap. > > Please explain ? Draw to a bitmap and in OnPaint draw that. Similar to a TImage. Then you can also use aggpas.

I thought lazarus did double buffering by default, so this should be so automatically ?

Michael.

Reply by email

Graeme Geldenhuys
to Mattias Gaertner: On Mon, 10 Oct 2016 12:05:41 +0200 (CEST) Draw to a bitmap and in OnPaint draw that.…
Mattias Gaertner wrote
Draw to a bitmap and in OnPaint draw that. Similar to a TImage. Then you can also use aggpas.

Incidently, that is how fpGUI's latest 'develop' branch overcomes the painting outside the Paint method problems. Seeing as AggPas is used as the internal buffer, it doesn't matter when painting calls happen. The actual Paint() method simply bitblt's the AggPas buffer to the real window canvas.

Regards,
Graeme

fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal http://fpgui.sourceforge.net/ My public PGP key: http://tinyurl.com/graeme-pgp

Reply by email

Graeme Geldenhuys
to Michael Van Canneyt: I thought lazarus did double buffering by default, so this should be so automatically ?…
Michael Van Canneyt wrote
I thought lazarus did double buffering by default, so this should be so automatically ?

I don't believe LCL uses double buffering by default (for some reason or another). At least that is what I was told in the Lazarus Forums.

Regards,
Graeme

fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal http://fpgui.sourceforge.net/ My public PGP key: http://tinyurl.com/graeme-pgp

Reply by email

zeljko
to Graeme Geldenhuys: Working on a visual report designer for the upcoming fpReport. We use…
Graeme Geldenhuys wrote 11 lines
Hi, Working on a visual report designer for the upcoming fpReport. We use Canvas.DrawFocusRect() to draw a selection rectangle around a reporting element (eg: a memo). We can drag that rectangle around in the report designer (which itself is a custom widget). We call the Canvas.DrawFocusRect() from within the MouseMove event. It seems to work fine under LCL-GTK2, but could this be problematic on other platforms, as painting outside the Paint event can normally have undefined results. Or has LCL somehow resolved the issues of painting outside the Paint event?

No, carbon, cocoa and qt widgetset (qt on all platforms) cannot paint outside of paint event.
FocusRect(s) can be saved in an object or array of focus TRectangles, Update() or Update(RectToBeUpdated) can be called from MouseMove, and then in paint method paint saved FocusRect(s).

zeljko

Reply by email

Mattias Gaertner
to Michael Van Canneyt: I thought lazarus did double buffering by default, so this should be so automatically ?…
Show quoted text 15 lines
On Mon, 10 Oct 2016, Mattias Gaertner via Lazarus wrote: > On Mon, 10 Oct 2016 12:05:41 +0200 (CEST) > Michael Van Canneyt via Lazarus wrote: > >> [...] >> > If you want to optimize for mini changes like the focusrect you might >> > want to use a bitmap. >> >> Please explain ? > > Draw to a bitmap and in OnPaint draw that. Similar to a TImage. > Then you can also use aggpas. I thought lazarus did double buffering by default, so this should be so automatically ?

Double buffering means, that there are two buffers, one for showing and for painting. When painting is done they are "swapped". This avoids flickering. No more, no less.
What happens with the second buffer between two paint events is up to the widgetset. The buffer often does not contain your last painted bitmap.

Mattias

Reply by email

Mattias Gaertner
to Graeme Geldenhuys: I don't believe LCL uses double buffering by default (for some reason or another). At…
Show quoted text 5 lines
On 2016-10-10 11:50, Michael Van Canneyt via Lazarus wrote: > I thought lazarus did double buffering by default, so this should be so automatically ? I don't believe LCL uses double buffering by default (for some reason or another). At least that is what I was told in the Lazarus Forums.

Widgetsets forbidding to paint outside OnPaint always use double buffering.
Widgetsets that allow drawing outside give a choice. For historical reasons TWinControl.DoubleBuffered defaults to false.

Mattias

Reply by email

Michael Van Canneyt
to Mattias Gaertner: On Mon, 10 Oct 2016 12:50:26 +0200 (CEST) Double buffering means, that there are two…
Mattias Gaertner wrote 22 lines
On Mon, 10 Oct 2016 12:50:26 +0200 (CEST) Michael Van Canneyt wrote: > On Mon, 10 Oct 2016, Mattias Gaertner via Lazarus wrote: > > > On Mon, 10 Oct 2016 12:05:41 +0200 (CEST) > > Michael Van Canneyt via Lazarus wrote: > > > >> [...] > >> > If you want to optimize for mini changes like the focusrect you might > >> > want to use a bitmap. > >> > >> Please explain ? > > > > Draw to a bitmap and in OnPaint draw that. Similar to a TImage. > > Then you can also use aggpas. > > I thought lazarus did double buffering by default, so this should be so automatically ? Double buffering means, that there are two buffers, one for showing and for painting. When painting is done they are "swapped". This avoids flickering. No more, no less.

I understand that.

But the effect is that inside the Paint() event you are actually drawing to a bitmap (buffer), which is then swapped to the display once the paint method is done ?

So why would I want to introduce a third buffer, which is then copied to the second, which is then copied to the actual display ?

I thought the idea was to be more efficient, not less ?

Michael.

Reply by email

Mattias Gaertner
to Michael Van Canneyt
[...] But the effect is that inside the Paint() event you are actually drawing to a bitmap (buffer), which is then swapped to the display once the paint method is done ?

The effect is that you can do small draws inside and outside the paint event and only need a draw bitmap in OnPaint. Which depending on your control might be faster than drawing everything on every OnPaint.

If you instead can optimize your OnPaint event you don't need this bitmap.

And if you target only Windows+Gtk, you can draw outside OnPaint and don't need the bitmap either.

So why would I want to introduce a third buffer, which is then copied to the second, which is then copied to the actual display ?

Copying compatible bitmaps is pretty fast.

Mattias

Reply by email

Alexey
to Alexey
Alexey wrote
remove that Debug line which prints error.

I misread the subject: I mean that debug line-

user at user-Notebook:~$ cudatext
WARNING: TGtk2WidgetSet.InvalidateRect refused invalidating during paint message: TATSynEdit
WARNING: TGtk2WidgetSet.InvalidateRect refused invalidating during paint message: TATSynEdit
WARNING: TGtk2WidgetSet.InvalidateRect refused invalidating during paint message: TATSynEdit
WARNING: TGtk2WidgetSet.InvalidateRect refused invalidating during paint message: TATSynEdit
WARNING: TGtk2WidgetSet.InvalidateRect refused invalidating during paint message: TATSynEdit
WARNING: TGtk2WidgetSet.InvalidateRect refused invalidating during paint message: TATSynEdit

Regards, Alex

Reply by email

Mattias Gaertner
to Alexey
Show quoted text 8 lines
On 11.10.2016 04:29, Alexey via Lazarus wrote: > remove that Debug line which prints error. I misread the subject: I mean that debug line- user at user-Notebook:~$ cudatext WARNING: TGtk2WidgetSet.InvalidateRect refused invalidating during paint message: TATSynEdit

That's not a debug line. It's a warning, that the GTK interface had to break an endless loop.
Please create bug report with an example to reproduce this.

Mattias

Reply by email

Juha Manninen
to Alexey
Alexey wrote
Hm, this is work to make an example; why not to comment this msg in GTK2 widget?

You can comment it. You have the sources.
However it must be kept in the public sources because it is a valid warning.

Juha

Reply by email