Copyrect not working in Linux lazarus / 39-Graphics ---------------------------------------------------------------------- rebzdu · 2020-11-30 19:47 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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i TempBild:TImage;TempBild is created by Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i TempBild.Free;TempBild:=TImage.Create(Form1);TempBild.Left := 0;TempBild.Top := 0;TempBild.Width := Form1.ClientWidth;TempBild.Height := Form1.ClientHeight;With TempBild,Canvas do    begin    Brush.Color := clRed;{bz White;}    FillRect(Rect(0,0,ClientWidth,ClientHeight));    Font.Name := 'Arial';    Font.Size := 10;    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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i with TempBild.Canvas do    src := Rect(0,0,ClientWidth,ClientHeight);with Form1.Canvas do    dest := Rect(0,0,ClientWidth,ClientHeight);Form1.Ca nvas.CopyRect(dest,TempBild.Canvas,src); but nothing happens, in on my screen. With older versions of Lazarus under Linux everything worked satisfactory. Can anybody help me? ---------------------------------------------------------------------- winni · 2020-11-30 20:14 Hi! A canvas does not have a clientRect, clientWidth, ClientHeight. So the source rect has to be: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i 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 ---------------------------------------------------------------------- Thaddy · 2020-11-30 20:42 Quote from: winni on November 30, 2020, 09:14:27 pmf 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. ---------------------------------------------------------------------- winni · 2020-11-30 22:48 Quote from: Thaddy on November 30, 2020, 09:42:59 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 ---------------------------------------------------------------------- rebzdu · 2020-12-01 00:06 Hallo winni, I put it inside of FormPaint, and now it is also running with Lazarus on my Linux-PC  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? ---------------------------------------------------------------------- rebzdu · 2020-12-01 18:44 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 ---------------------------------------------------------------------- Thaddy · 2020-12-01 20:11 You should follow my advice, not winni. He is mistaken. ---------------------------------------------------------------------- winni · 2020-12-01 20:28 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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.FormPaint(Sender: TObject);...begin                                     self.Canvas.CopyRect(dest,TempBild.Canvas,src);...end;  Winni ---------------------------------------------------------------------- rebzdu · 2020-12-01 20:29 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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i     BeginUpdate;    Form1.Canvas.CopyRect(dest,TempBild.Canvas,src);    EndUpdate; in my code I get the message "Error illegal qualifier" ---------------------------------------------------------------------- Sieben · 2020-12-01 20:37 TCanvas has Lock, TryLock and Unlock... ---------------------------------------------------------------------- rebzdu · 2020-12-01 20:55 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. ---------------------------------------------------------------------- winni · 2020-12-01 22:23 Hi! That's the difference between theory (Thaddy)  and practice (Me). Winni ---------------------------------------------------------------------- lucamar · 2020-12-01 23:45 Quote from: rebzdu on December 01, 2020, 09:55:44 pmBut 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 ... ---------------------------------------------------------------------- rebzdu · 2020-12-02 00:43 I don't call it by FormPaint, but at the end of my method I call Repaint: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.ZeigeTempBild;var src,dest:TRect;begin{$IFDEF DUMP}Append(log); writeln(log,'ZeigeTempBild');CloseFile(log);{$ENDIF}//TempBild.Picture .SaveToFile('TempBild '+IntToStr(BildNr)+'.jpg');with TempBild do    src := Rect(0,0,Width,Height);with Form1.Canvas do    dest := Rect(0,0 ,ClientWidth,ClientHeight);Canvas.Lock;Canvas.CopyRect(dest,TempBild.C anvas,src);Canvas.Unlock;Repaint;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. ---------------------------------------------------------------------- circular · 2020-12-03 11:33 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. ---------------------------------------------------------------------- rebzdu · 2020-12-03 14:06 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. ---------------------------------------------------------------------- circular · 2020-12-03 14:28 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. ---------------------------------------------------------------------- rebzdu · 2020-12-05 00:17 Quote from: circular on December 03, 2020, 03:28:33 pmI 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. Quote from: circular on December 03, 2020, 03:28:33 pmDoing 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 ---------------------------------------------------------------------- circular · 2020-12-05 08:55 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. QuoteNow 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. Quote from: rebzdu on December 05, 2020, 01:17:47 amI don't thing that I need TBitmap, TImage is sufficientIn 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. QuoteQuote from: circular on December 03, 2020, 03:28:33 pmDoing 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 CopyRectThe 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.