Lazarus

Programming => Graphics and Multimedia => Graphics => Topic started by: rebzdu on November 30, 2020, 08:47:16 pm

Title: Copyrect not working in Linux
Post by: rebzdu on November 30, 2020, 08:47:16 pm
I have a program, which was working fine in Windows and Linux.
Shortly I recompiled the source in Linux with Lazarus Version #: 2.1.0, Date 2020-05-30, FPC-Version: 3.0.4, SVN-Revision 63251M, x86_64-linux-gtk2.
I draw an image in the background on
Code: Pascal  [Select][+][-]
  1. TempBild:TImage;
TempBild is created by
Code: Pascal  [Select][+][-]
  1. TempBild.Free;
  2. TempBild:=TImage.Create(Form1);
  3. TempBild.Left := 0;
  4. TempBild.Top := 0;
  5. TempBild.Width := Form1.ClientWidth;
  6. TempBild.Height := Form1.ClientHeight;
  7. With TempBild,Canvas do
  8.     begin
  9.     Brush.Color := clRed;{bz White;}
  10.     FillRect(Rect(0,0,ClientWidth,ClientHeight));
  11.     Font.Name := 'Arial';
  12.     Font.Size := 10;
  13.     end;
To check, if everything is well drawn I tested it by
Code: [Select]
TempBild.Picture.SaveToFile('TempBild.jpg');and everything is fine
I transfer it to the Canvas of Form1 with the following statements:
Code: Pascal  [Select][+][-]
  1. with TempBild.Canvas do
  2.     src := Rect(0,0,ClientWidth,ClientHeight);
  3. with Form1.Canvas do
  4.     dest := Rect(0,0,ClientWidth,ClientHeight);
  5. Form1.Canvas.CopyRect(dest,TempBild.Canvas,src);
  6.  
but nothing happens, in on my screen.
With older versions of Lazarus under Linux everything worked satisfactory.
Can anybody help me?
Title: Re: Copyrect not working in Linux
Post by: winni on November 30, 2020, 09:14:27 pm
Hi!

A canvas does not have a clientRect, clientWidth, ClientHeight.
So the source rect has to be:

Code: Pascal  [Select][+][-]
  1. src := Rect(0,0, TempBild.Width,TempBild.Height);

Second:

If you copy from canvas to canvas this has to be done in the OnPaint event of Form1.
This is not clear from your source.

Winni


Title: Re: Copyrect not working in Linux
Post by: Thaddy on November 30, 2020, 09:42:59 pm
f you copy from canvas to canvas this has to be done in the OnPaint event of Form1.
No, the canvas should be locked/unlocked with beginupdate/endupdate. OnPaint has nothing to do with it. On the contrary, you should prevent access - so prevent paint at all during the operation..
Although this can be achieved in OnPaint (provided the locking) that is not the correct spot.
BeginUpdate prevents any painting, so logically the wrong place for "OnPaint"....because there is no paint....
Basically you can do it anywhere, but make sure you use BeginUpdate/EndUpdate.
Only after that - this is a blocking operation - you should use OnPaint to show the results if necessary.
Or call paint.
Title: Re: Copyrect not working in Linux
Post by: winni on November 30, 2020, 11:48:53 pm

Basically you can do it anywhere, but make sure you use BeginUpdate/EndUpdate.


Very wise.

After the next hiding the app the drawaing on the Form.canvas is gone.
You come along and repaint it? Or who?

Winni

Title: Re: Copyrect not working in Linux
Post by: rebzdu on December 01, 2020, 01:06:03 am
Hallo winni,
I put it inside of FormPaint, and now it is also running with Lazarus on my Linux-PC  ;D

Hallo Thaddy
I tried to put it outside of FormPaint, but Lazarus complains, that there is no beginupdate resp. endupdate. TForm knows BeginFormUpdate/EndFormUpdate (did ypu mean this?), but  this didn't work as well, even if I call Paint resp. Invalidate/Paint after using CopyRect.  :(

What I don't understand, why my code was running one year ago on Windows and Linux, now only on Windows. On Linux I have the newest Version of Lazarus, on Windows I use an earlier version. Have there been any changes to CopyRect, so that FormPaint/Paint was called automatically in the previsous versions of Lazarus?
Title: Re: Copyrect not working in Linux
Post by: rebzdu on December 01, 2020, 07:44:59 pm
Hello winni,
if I put it inside FormPaint, my Windows-Version is no longer working. There are white flashes between my own images in irregular intervals and my keystokes are no longer recognized  :(
Title: Re: Copyrect not working in Linux
Post by: Thaddy on December 01, 2020, 09:11:26 pm
You should follow my advice, not winni. He is mistaken.
Title: Re: Copyrect not working in Linux
Post by: winni on December 01, 2020, 09:28:07 pm
Hi!

In Thaddys mind I am allways wrong...

The error has another reason:

Never call Form1 in a procedure TForm1.......

The correct way is  :
Code: Pascal  [Select][+][-]
  1. procedure TForm1.FormPaint(Sender: TObject);
  2. ...
  3. begin                                      
  4. self.Canvas.CopyRect(dest,TempBild.Canvas,src);
  5. ...
  6. end;
  7.  

Winni
Title: Re: Copyrect not working in Linux
Post by: rebzdu on December 01, 2020, 09:29:46 pm
Hello Thaddy,
as I wrote this morning, Lazarus doesn't know BeginUpdate and EndUpdate, these aren't methods from TForm nor from TCanvas.
If I insert
Code: Pascal  [Select][+][-]
  1.     BeginUpdate;
  2.     Form1.Canvas.CopyRect(dest,TempBild.Canvas,src);
  3.     EndUpdate;
in my code I get the message
"Error illegal qualifier"
Title: Re: Copyrect not working in Linux
Post by: Sieben on December 01, 2020, 09:37:51 pm
TCanvas has Lock, TryLock and Unlock...
Title: Re: Copyrect not working in Linux
Post by: rebzdu on December 01, 2020, 09:55:44 pm
Now I can compile without error messages.
But if I put the code outside of FormPaint, nothing happens, only if I insert it inside FormPaint.
Title: Re: Copyrect not working in Linux
Post by: winni on December 01, 2020, 11:23:50 pm
Hi!

That's the difference between theory (Thaddy)  and practice (Me).

Winni
Title: Re: Copyrect not working in Linux
Post by: lucamar on December 02, 2020, 12:45:17 am
But if I put the code outside of FormPaint, nothing happens, only if I insert it inside FormPaint.

I don't know how you're putting the code "outside of FormPaint" but, of course, you can put in any method/procedure/function. Only, it has to be called from the OnPaint handler (or similar); otherwise it'll never be executed! Code outside event handlers has to be called from somewhere ... ;D
Title: Re: Copyrect not working in Linux
Post by: rebzdu on December 02, 2020, 01:43:25 am
I don't call it by FormPaint, but at the end of my method I call Repaint:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.ZeigeTempBild;
  2. var src,dest:TRect;
  3. begin
  4. {$IFDEF DUMP}
  5. Append(log);
  6. writeln(log,'ZeigeTempBild');
  7. CloseFile(log);
  8. {$ENDIF}
  9. //TempBild.Picture.SaveToFile('TempBild '+IntToStr(BildNr)+'.jpg');
  10. with TempBild do
  11.     src := Rect(0,0,Width,Height);
  12. with Form1.Canvas do
  13.     dest := Rect(0,0,ClientWidth,ClientHeight);
  14. Canvas.Lock;
  15. Canvas.CopyRect(dest,TempBild.Canvas,src);
  16. Canvas.Unlock;
  17. Repaint;
  18. end;
The Method is call by a timer every second, which I controlled by the log-file. If I uncomment line 9 I get the propper images on my hard disk.
If I put lines 9-16 into FormPaint, it works in Linux, but I get the problems in Windows.
Title: Re: Copyrect not working in Linux
Post by: circular on December 03, 2020, 12:33:21 pm
I am confused. Is TempBild just to store an image that is not visible? If that's the case, then you would rather use TBitmap. And it is easy to draw a bitmap on a Canvas using the Draw function.

TImage is a visual component and its Canvas is not meant to store a bitmap. Though if you want to store a bitmap in it, you can use its Picture.Bitmap property.

Painting on the form, in order to be cross platform should be done only in the OnPaint events. Otherwise it won't work on Qt5 or MacOS.
Title: Re: Copyrect not working in Linux
Post by: rebzdu on December 03, 2020, 03:06:58 pm
I use TImage.Canvas to draw in the background. If the drawing is complete, I put it in the foreground with CopyRect.
Everything worked find till last year. Now I recompiled the source and have the problems.
If I draw directly in the Canvas of Form1, the screen is flickering, bacause there is a lot to draw.
Title: Re: Copyrect not working in Linux
Post by: circular on December 03, 2020, 03:28:33 pm
I think you're confused. You don't put a component in foreground with CopyRect. If you want the component to be visible, you would use its Visible property or call the BringToFront function.

Doing CopyRight from the canvas of a component that is not visible is not supposed to work. You were just lucky it worked until now, but that's really not guaranteed to work, depending on the version of the OS or the widgetset.

If you don't want it to flicker, to draw it in one go, you can do that with a TBitmap. That's an image that is not a component, not supposed to be visible, but that you can draw on a surface.

You can achieve this by creating a TBitmap, set its Width and Height, and use its Canvas property. Then put it on the form using the Draw function of the form canvas.
Title: Re: Copyrect not working in Linux
Post by: rebzdu on December 05, 2020, 01:17:47 am
I think you're confused. You don't put a component in foreground with CopyRect.
Perhaps this is my bad english that leads to misunderstandings.

I didn't think, that I put my TempImage in the foreground,
I am aware, that CopyRect makes a copy from its own Canvas to the Canvas of Form1.
I am painting in the background on TempImage (not visible) while the previous image (canvas) of Form1 is visible.

I don't thing that I need TBitmap, TImage is sufficient, which I saw, when I checked my drawing with a call of
Code: [Select]
TempBild.Picture.SaveToFile('TempBild.jpg'); The image, I find afterwards on my harddisk is the one I expected.

Doing CopyRight from the canvas of a component that is not visible is not supposed to work.
I have never seen any supporting document, which mention, that it is necessary, that the image must be visible whilst you call CopyRect

Meanwhile I solved the problem of the flickering in my Windows-Version.
When I created my program (in 1993, with Turbo Pascal/Delphi) my memory was running out, so I set
Code: [Select]
Form1.DoubleBuffered := false to save some memory space.
Meanwhile I have enough memory, that this is no longer necessary, but I didn't kick out this instruction, because there were no problems till now.
Now I had to put CopyRect within FormPaint (see my posts above), so I generated a flickering image in Windows (not in Linux).

Strangely enough, till these changes my program doesn't react to any keystroke after the first one is processed in the Windows-version, but this is another problem.

I'd like to know, why CopyRect must be done within FormPaint, but it is not vital, so my oroiginal problem is solved.

Thanks to everyone

rebzdu
Title: Re: Copyrect not working in Linux
Post by: circular on December 05, 2020, 09:55:45 am
I have the impression I scared you off.  :'(

You are free to do as you wish. I am just trying to explain so that you have a reliable way of doing things.

Quote
Now I had to put CopyRect within FormPaint (see my posts above), so I generated a flickering image in Windows (not in Linux).
The OnPaint event happens just after the background of the form is cleared. So that's the best place to minimize flickering.

If you want to avoid flickering, you can as well disable the LM_ERASEBKGND message and draw in the OnPaint event. So whenever the forms get invalidated, you would redraw its content and there would be no flickering at all.

As I said before, on certain widgetsets, like Qt5 or MacOS, you cannot draw outside of OnPaint at all. That would just display nothing. So it is a good habit to always draw on the controls in OnPaint.

I don't thing that I need TBitmap, TImage is sufficient
In my view, it is the other way around. TImage is TBitmap + a control to display on the screen. So TBitmap is sufficient and TImage is superfluous.

Quote
Doing CopyRight from the canvas of a component that is not visible is not supposed to work.
I have never seen any supporting document, which mention, that it is necessary, that the image must be visible whilst you call CopyRect
The Canvas of the control is the screen unless the system or framework creates a bitmap to store its content (like DoubleBuffered). So doing the CopyRect could just try to copy the pixels from the screen.

TImage.Canvas: the screen or some double-buffer
TImage.Picture.Bitmap.Canvas: the canvas of the image that is supposed to be stored in TImage

That means that there are 3 surfaces here: the screen, the double-buffer, and the image (Picture) that can be stored in TImage.

You could in fact just make the TImage visible and draw in its Picture.Bitmap. This would be a way to use TImage that would make more sense. And enable DoubleBuffer on the form to avoid any flickering when the TImage gets repainted.
TinyPortal © 2005-2018