Recent

Author Topic: Draw on Canvas - cannot fathom the logic  (Read 10290 times)

J-G

  • Hero Member
  • *****
  • Posts: 953
Draw on Canvas - cannot fathom the logic
« on: May 17, 2017, 01:47:38 pm »
I have an array of data which currently has 7 records ([0..6]). When displayed, I want one of the fields to be highlighted with a 'bounding box' and two elements (which are static) to be separated by a 'line'.

I have no problem in determining where and how the box and line are drawn but as I scroll through the records, two of them refuse to display the box and line. Not only that, if I scroll 'forward' ( 0 > > 6 ) the first and last display incorrectly but if I scroll 'backward' ( 6 > > 0 ) then records 5 and 6 are affected.

The attached screen shot shows the display of records 5 and 6 when going forward.

I have tested the code with the call to [DrawLines] in [ShowVATReturn] as well as each of the [Prev] and [Next] procedures but the result is the same.

Code: Pascal  [Select][+][-]
  1. procedure DrawLines;
  2. begin
  3.   with Form1.VATPanel.Canvas do
  4.    begin
  5.      Pen.Width := 3;
  6.      Pen.Color := DefCol;
  7.      Line(5,62,233,62);
  8.      Rectangle(124,145,232,172);
  9.    end;
  10. end;
  11.  
  12. procedure ShowVATReturn;
  13. begin
  14. [...]
  15.  
  16. //  DrawLines;
  17. end;
  18.  
  19. procedure TForm1.NextPeriodClick(Sender: TObject);
  20. begin
  21.   inc(VATRet_InUse);
  22.   if VATRet_InUse > VATCount then
  23.     VATRet_InUse := 0;
  24.  
  25.   VAT_Ret := VAT_Array[VATRet_InUse];
  26.   Period.Caption := VAT_Array[VATRet_InUse].Period;
  27.  
  28.   ShowVATReturn;
  29.  
  30.   DrawLines;
  31. end;
  32. procedure TForm1.PrevPeriodClick(Sender: TObject);
  33. begin
  34.   dec(VATRet_InUse);
  35.   if VATRet_InUse = 255 then
  36.     VATRet_InUse := VATCount;
  37.  
  38.   VAT_Ret := VAT_Array[VATRet_InUse];
  39.   Period.Caption := VAT_Array[VATRet_InUse].Period;
  40.  
  41.   ShowVATReturn;
  42.  
  43.   DrawLines;
  44. end;
  45.  

I've removed the 'detail' in the [ShowVATReturn] as it is quite long and is just code to fill the TLabel.Caption fields.

I just cannot see how the DrawLines procedure knows  -  or cares  -  which record is being shown!
FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0 
Win 7 Ult 64

Handoko

  • Hero Member
  • *****
  • Posts: 5122
  • My goal: build my own game engine using Lazarus
Re: Draw on Canvas - cannot fathom the logic
« Reply #1 on: May 17, 2017, 02:15:19 pm »
Hi J-G.

Can you provide us the compilable and runable code for us to test. Bugs can happen anywhere in the code, it is very hard to debug from what you provided now, we cannot run and test it.

I understand for certain reason you may not willing to publicize your project. You can write a test project simply showing the bug, compress and attach all the necessary files to this forum. If it uses database, please also provide it.

Also, can you tell us what OS you're using? And what your Lazarus and FPC version is.
« Last Edit: May 17, 2017, 02:17:37 pm by Handoko »

sky_khan

  • Guest
Re: Draw on Canvas - cannot fathom the logic
« Reply #2 on: May 17, 2017, 02:15:58 pm »
Canvas drawings are not persistent. They need to be drawn everytime in OnPaint event (if exists) or in wm_paint message handler. I guess you draw those lines outside of these procedures so other elements/components cover the lines when they are drawn.

wp

  • Hero Member
  • *****
  • Posts: 11833
Re: Draw on Canvas - cannot fathom the logic
« Reply #3 on: May 17, 2017, 02:29:39 pm »
SkyKhan is correct: You must draw the text in the OnPaintEvent of the form.
« Last Edit: May 17, 2017, 04:59:07 pm by wp »

J-G

  • Hero Member
  • *****
  • Posts: 953
Re: Draw on Canvas - cannot fathom the logic
« Reply #4 on: May 17, 2017, 03:21:38 pm »
@ handoko
I don't really have a problem with publicizeing my project (even though, as you've understood, the data is 'live' and personal) except that it is some 12000 lines long and calls on 26 databases of information! 

I'm running on Win 7 Ultimate 64, Laz 1.6 FPC 3.0

I might be able to extract the part of the code that deals with just the display of the VAT Returns and make it a completely new project  -  though I'm not convinced that would lead to a solution. 

My question is more to do with why records 1 to 5 (or 0 to 4) display correctly but the others do not.

@ SkyKhan & wp
Whilst I can see your points, I do actually draw the box/line every time the data is refreshed.

I also make [DrawLines] the last call so that they are on top of anything already on the canvas.

In case it is beneficial this is the code that writes the VAT_Due figure - just before DrawLines is called :

Code: Pascal  [Select][+][-]
  1.   if VAT_Ret.Value < 0 then
  2.     Form1.vat_Due.font.Color := clRed
  3.   else
  4.     Form1.vat_Due.font.Color := clBlack;
  5.   Form1.vat_Due.Caption := StringValue(Abs(VAT_Ret.Value),True);
  6.  

[StringValue] is a 'Helper' type function which formats the value received and adds the currency sign (or not).

I've even looked at the Borderspacing Properties of the TLabel  to see if that might be used to 'highlight' the figure (without success).

« Last Edit: May 17, 2017, 03:30:32 pm by J-G »
FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0 
Win 7 Ult 64

wp

  • Hero Member
  • *****
  • Posts: 11833
Re: Draw on Canvas - cannot fathom the logic
« Reply #5 on: May 17, 2017, 03:43:51 pm »
Whilst I can see your points, I do actually draw the box/line every time the data is refreshed.

I also make [DrawLines] the last call so that they are on top of anything already on the canvas.
The times of DOS when the screen was under your control alone are long gone. Your program cannot control if the OS wants to repaint your windows. Suppose your program is running and all your user-drawn code has been executed correctly. But then you decide to switch to the browser and look for something. When you return to your program the OS will repaint your form. But the form's Paint method does not know about the additional code in DrawLine. The only way to make user-drawn code being executed whenever needed is to put it into the OnPaint event (or call it from there).

In order to draw the thick box your navigation code must store some information on which record will get the highlighting border and/or the coordinates of the box rectangle in some local form variables, and it must call Invalidate to retrigger a paint cycle of the form. The Form's OnPaint must draw the rectangle.

Maybe the attached demo is of any help

sky_khan

  • Guest
Re: Draw on Canvas - cannot fathom the logic
« Reply #6 on: May 17, 2017, 04:40:36 pm »
Even no need for overlapping windows/controls :) Minimize and restore your application and all your custom drawings are gone.
There is no any reliable way to draw on canvas of any control outside of paint cycle. You should do all your drawings in wm_paint handler. Period.
Some controls provides OnPaint event which is called by wm_paint. You need to use one of them or you may write your own control and draw whatever you want in it's wm_paint handler.
« Last Edit: May 17, 2017, 04:43:15 pm by SkyKhan »

J-G

  • Hero Member
  • *****
  • Posts: 953
Re: Draw on Canvas - cannot fathom the logic
« Reply #7 on: May 17, 2017, 07:58:27 pm »
Thanks wp -  sorted!  (and SkyKhan)

The times of DOS when the screen was under your control alone are long gone.
I will pull myself out of the DOS environment !! promise :)
Quote from: wp
Your program cannot control if the OS wants to repaint your windows. Suppose your program is running and all your user-drawn code has been executed correctly. But then you decide to switch to the browser and look for something. When you return to your program the OS will repaint your form. But the form's Paint method does not know about the additional code in DrawLine.
Oddly enough, I did do this test and it was negative  -  ie. I dragged other program windows over my form which had the box and line showing and they were still there when I moved the window away. In the light of SkyKhan's suggestion of minimize and restore, I found that that did destroy the box/line, as did dragging my window off the edge of the screen and back again.
Quote from: wp
The only way to make user-drawn code being executed whenever needed is to put it into the OnPaint event (or call it from there).
(or call it from there) This is a 'Key' statement  - - -  I've created an OnPaint event which just calls the DrawLine procedure and Voila! box and line appear on every record  :D :D
Quote from: wp
In order to draw the thick box your navigation code must store some information on which record will get the highlighting border and/or the coordinates of the box rectangle in some local form variables, and it must call Invalidate to retrigger a paint cycle of the form. The Form's OnPaint must draw the rectangle.

Maybe the attached demo is of any help
I've played a little with the demo and can see some useful bits of code. As yet I haven't needed to add 'Invalidate' so can't fully understand the implications. I'll have to spend more time 'playing'.



FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0 
Win 7 Ult 64

Mr.Madguy

  • Hero Member
  • *****
  • Posts: 844
Re: Draw on Canvas - cannot fathom the logic
« Reply #8 on: May 17, 2017, 09:11:31 pm »
Oddly enough, I did do this test and it was negative  -  ie. I dragged other program windows over my form which had the box and line showing and they were still there when I moved the window away. In the light of SkyKhan's suggestion of minimize and restore, I found that that did destroy the box/line, as did dragging my window off the edge of the screen and back again.
It works like this since Vista, when built-in double-buffering was implemented. On XP and older systems - system calls WM_PAINT every time, when your window needs to be painted on a screen. That's because older computers had lesser memory and OS developers didn't want to take such responsibility, as implementing double-buffering by default - it was your responsibility. If you wouldn't properly respond to this event on old OS - you would see desktop inside your window's border. That's, what sometimes happens, when application hangs or works too slowly. I think, you should design your application with this behaviour in mind for backwards compatibility.

If you want an example of proper control implementation - use this example as reference.
« Last Edit: May 17, 2017, 09:32:53 pm by Mr.Madguy »
Is it healthy for project not to have regular stable releases?
Just for fun: Code::Blocks, GCC 13 and DOS - is it possible?

BeanzMaster

  • Sr. Member
  • ****
  • Posts: 268
Re: Draw on Canvas - cannot fathom the logic
« Reply #9 on: May 18, 2017, 02:46:59 pm »
Hi you can try to add "changed" at the end of your code, or try to force with Repaint/Resfresh/Invalidate

Code: Pascal  [Select][+][-]
  1. procedure DrawLines;
  2. begin
  3.   with Form1.VATPanel.Canvas do
  4.    begin
  5.      Pen.Width := 3;
  6.      Pen.Color := DefCol;
  7.      Line(5,62,233,62);
  8.      Rectangle(124,145,232,172);
  9.      Changed; // Try by adding this line
  10.    end;
  11. end;

Best regards


RAW

  • Hero Member
  • *****
  • Posts: 868
Re: Draw on Canvas - cannot fathom the logic
« Reply #10 on: May 22, 2017, 12:34:20 am »
Maybe I miss the mark, but I would draw such lines in OnCreate and assign the bitmap to a TIMAGE...  done...  :P
Windows 7 Pro (x64 Sp1) & Windows XP Pro (x86 Sp3).

Thaddy

  • Hero Member
  • *****
  • Posts: 14169
  • Probably until I exterminate Putin.
Re: Draw on Canvas - cannot fathom the logic
« Reply #11 on: May 22, 2017, 07:15:22 am »
Maybe I miss the mark, but I would draw such lines in OnCreate and assign the bitmap to a TIMAGE...  done...  :P
You missed the mark it in sofar that you - probably unintentionally - implement a buffered pattern. That's not necessary, because that can also be done by the doublebuffered property.
Also, on further painting you will loose the benifit of regions and clipping so it can make your application dead slow if painting is dynamic.
If painting is static, the image doesn't change, your method would imply it's better to do the painting during development, save it and add it as a resource.

But Heey it works! if the image needs no further change....
Specialize a type, not a var.

J-G

  • Hero Member
  • *****
  • Posts: 953
Re: Draw on Canvas - cannot fathom the logic
« Reply #12 on: May 22, 2017, 05:23:52 pm »
@ BeanzMaster
Although your suggestion came well after I (actually wp) had solved my problem I did look to see if it worked.   -  It didn't  -   I presume because I would also need to add another [Uses] clause.  simply adding 'created;' or 'Invalidate;' to the end of the [DrawLine] Proc wouldn't compile.

@ RAW
Your suggestion is beyond my comprehension, so maybe I also 'miss your mark'. The VATPanel is only shown as and when required rather than an integral part of the main form.

@ Thaddy
As you surmise, calling [DrawLines] from the [OnPaint] event works and no further change is needed.

Thanks to all for continued interest.
FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0 
Win 7 Ult 64

Zath

  • Sr. Member
  • ****
  • Posts: 391
Re: Draw on Canvas - cannot fathom the logic
« Reply #13 on: May 22, 2017, 06:57:24 pm »
@ handoko
I don't really have a problem with publicizeing my project (even though, as you've understood, the data is 'live' and personal) except that it is some 12000 lines long and calls on 26 databases of information! 

Please, please don't do work like this on live, real data. Even if what you're doing isn't directly involved with the data, you know what's going to happen.
Been there ....


J-G

  • Hero Member
  • *****
  • Posts: 953
Re: Draw on Canvas - cannot fathom the logic
« Reply #14 on: May 22, 2017, 08:22:35 pm »
@ handoko
I don't really have a problem with publicizeing my project (even though, as you've understood, the data is 'live' and personal) except that it is some 12000 lines long and calls on 26 databases of information! 

Please, please don't do work like this on live, real data. Even if what you're doing isn't directly involved with the data, you know what's going to happen.
Been there ....
:D :D :D
Haven't we all !!

One of the first things that I code when working on a project involving databases is a [MakeBackup] procedure. This is called EVERY time data is written to any file. Not only that, I always 'step through' new code watching variables and stop the run if I see an error.

That doesn't mean that I don't create errors in the data but I can always write correction procedures should that become necessary.

FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0 
Win 7 Ult 64

 

TinyPortal © 2005-2018