Recent

Author Topic: Timing of capturing a control's image to a bitmap  (Read 879 times)

vsajip

  • New Member
  • *
  • Posts: 22
Timing of capturing a control's image to a bitmap
« on: May 29, 2025, 05:28:29 pm »
I'm trying to get an image of a control on a form just after it's been painted for the first time. I do this using

Code: Pascal  [Select][+][-]
  1.   with anImage do begin
  2.     Width := aControl.Width;
  3.     Height := aControl.Height;
  4.     with Picture.Bitmap do
  5.     begin
  6.       SetSize(aControl.Width, aControl.Height);
  7.       aControl.PaintTo(Canvas, 0, 0);
  8.     end;
  9.   end;

which works fine in itself, but timing is crucially important. I tried a number of things (on Linux, using GTK2):
  • Run the capture code above on the form's OnShow event. No dice - a black rectangle is captured.
  • In the OnShow handler, call QueueAsyncCall to another method, where I run the capture code. No dice again - a black rectangle is captured.
  • In the OnShow handler, I start a one-shot TTimer and run the capture code when it triggers. This works, if the timer interval is set to 100 ms on my machine. For smaller values, you get either a black rectangle or a rectangle the colour of the form background. But with a long enough interval, the control's appearance is faithfully captured.
This isn't ideal, but I couldn't find any other documented way of doing this more reliably. Does anyone know of any more reliable way of doing this capture which doesn't involve waiting for what is essentially an arbitrary length of time? The timer interval might need tweaking on slower machines, for example.

I need this because after doing the capture, I need to call a method on the control which changes its appearance. However, I need a record of the original appearance.

Any help gratefully received!

jamie

  • Hero Member
  • *****
  • Posts: 6960
Re: Timing of capturing a control's image to a bitmap
« Reply #1 on: May 29, 2025, 05:42:01 pm »
 You will need to use a different approach.

 There are limitations to the PaintTo, meaning in my exprerience you the control actually needs to be showing before you will get an image.

 Maybe you can try using the OnPaint event of the control if it has one, if not, you might be able to hook into it and capture the image then.

Jamie

The only true wisdom is knowing you know nothing

vsajip

  • New Member
  • *
  • Posts: 22
Re: Timing of capturing a control's image to a bitmap
« Reply #2 on: May 29, 2025, 06:52:41 pm »
> There are limitations to the PaintTo, meaning in my exprerience you the control actually needs to be showing before you will get an image.

Yes, that's what I'm trying to do - get the control's image as soon as practicable after its shown. Unfortunately it doesn't expose a Paint method nor an OnPaint event I can hook into, thus I've reluctantly resorted to the approach I outlined above  :(

jamie

  • Hero Member
  • *****
  • Posts: 6960
Re: Timing of capturing a control's image to a bitmap
« Reply #3 on: May 29, 2025, 07:20:41 pm »
Please indicate the Control type you are trying to capture, maybe a local class override can help.
The only true wisdom is knowing you know nothing

vsajip

  • New Member
  • *
  • Posts: 22
Re: Timing of capturing a control's image to a bitmap
« Reply #4 on: May 30, 2025, 11:16:27 am »
> Please indicate the Control type you are trying to capture, maybe a local class override can help.

It's a type of button, but I can't see how a local override would work - the control doesn't have any useful overridable methods for this use case. The only way of overriding I can see is if the base control has a Paint method, where one could override that, call Inherited to do the actual painting, and then run the capture code immediately after. Or were you thinking of something else?

jamie

  • Hero Member
  • *****
  • Posts: 6960
Re: Timing of capturing a control's image to a bitmap
« Reply #5 on: May 30, 2025, 11:42:06 am »
Have u tried first calling the paint handler prior to taking a snapshot?

Ims it should be "repaint".
The only true wisdom is knowing you know nothing

vsajip

  • New Member
  • *
  • Posts: 22
Re: Timing of capturing a control's image to a bitmap
« Reply #6 on: May 30, 2025, 12:52:50 pm »
> Have u tried first calling the paint handler prior to taking a snapshot?

Oh yes, it (Repaint) was among the first things I tried (in the OnShow handler). No dice - I got a black rectangle.

jamie

  • Hero Member
  • *****
  • Posts: 6960
Re: Timing of capturing a control's image to a bitmap
« Reply #7 on: May 30, 2025, 02:04:58 pm »
There must be a widget failure, this works on Win32.

You can hook into the paint handler for the control.

At the top of your source.
Code: Pascal  [Select][+][-]
  1. Type
  2.   TKnownControlClass = Class(UnitThatHoldsKnownControlClass.KnowControlClass)
  3.  
  4.   Procedure PaintHandler overridde; ....Etc
  5.  End;
  6.  
  7. Interfacesection
  8.  
  9.  procedure TKnownControlClass.PaintHandler;
  10.   Begin
  11.      Inherited;
  12.      // Now do your code here
  13.   End;
  14.  

 You may also want to test the name of the control to ensure you only do this trick when the interested control comes in.

 The above isn't exact but close enough for you to get the idea.
The only true wisdom is knowing you know nothing

vsajip

  • New Member
  • *
  • Posts: 22
Re: Timing of capturing a control's image to a bitmap
« Reply #8 on: May 30, 2025, 07:22:51 pm »
OK, thanks. I'm doing this on Linux but will look into your suggestions on this platform. Cheers!

wp

  • Hero Member
  • *****
  • Posts: 12867
Re: Timing of capturing a control's image to a bitmap
« Reply #9 on: May 30, 2025, 08:32:46 pm »
IIRC, the OnShow event is too early for this purpose. It fires when the Visible property becomes true and this does not necessarily mean that drawing is complete. When you hook into the onActivate event, which fires after OnShow, your code works.

vsajip

  • New Member
  • *
  • Posts: 22
Re: Timing of capturing a control's image to a bitmap
« Reply #10 on: May 31, 2025, 09:27:14 am »
> When you hook into the onActivate event, which fires after OnShow, your code works.

Is that on Windows, or Linux? On my Linux machine, calling the capture code in OnShow leads to a black rectangle, whereas calling it in OnActivate results in a rectangle the colour of the form background. The only way I could reliably get the image was to use a timer with a 100 ms interval. Smaller delays led to either black or form-background being captured.

wp

  • Hero Member
  • *****
  • Posts: 12867
Re: Timing of capturing a control's image to a bitmap
« Reply #11 on: May 31, 2025, 12:11:35 pm »
In the attachment I am sending a small demo which I used for testing, along with the OnShow and OnActivate bitmap files written by various widgetsets. Well, having the controls directly on a form is a bit tricky to work on all widgetsets: On Windows the left/top part of the window frame is caught, on cocoa both events lead to a black bitmap, on qtX the form background is drawn as a noisy pattern. Therefore, I decided to put all controls into a panel and to catch the bitmap from the panel only (I had to set its Color to white to avoid the qtX noise) - now the OnActivate images are always correct, and OnShow is always black (except for cocoa where it is painted partially (edit text missing)

vsajip

  • New Member
  • *
  • Posts: 22
Re: Timing of capturing a control's image to a bitmap
« Reply #12 on: May 31, 2025, 05:48:29 pm »
Thank you so much for this.

 

TinyPortal © 2005-2018