Recent

Author Topic: TControl and TGraphic Control creation issue  (Read 8274 times)

jcdammeyer

  • Full Member
  • ***
  • Posts: 205
  • Embedded System Developer
    • Automation Artisans Inc.
Re: TControl and TGraphic Control creation issue
« Reply #15 on: May 03, 2021, 11:34:48 pm »
The attached project makes a few adjustments to your main test program to create the component dynamically and exercise it.
To display a dynamically created control you need to set both its visual coordinates and its Parent (as well as any other relevant properties).
You don't need to explicitly call its Paint method. The LCL ensures that Paint is called whenever the OS needs to refresh the display.

Thank you.  I spent the entire weekend reading documents all the way back to my Borland Delphi 5 for Windows 98, 95 and NT.

The two major differences I see between my original and yours is the
      SetInitialBounds(10, 14, 130, 234);   // you had the LH point at 400

and
      Parent := Self;

I'm going to suspect that Parent is NIL on creation and that's why none of the Paint stuff worked properly.

It really appears to be that simple and perhap the SetInitialBounds is what is different between the Window Lazarus and the Linux Lazarus when it's installed as a component and dropped on the Form as shown in a previous posting.


jcdammeyer

  • Full Member
  • ***
  • Posts: 205
  • Embedded System Developer
    • Automation Artisans Inc.
Re: TControl and TGraphic Control creation issue
« Reply #16 on: May 04, 2021, 12:09:33 am »
I have one other related question to this issue of creating components.   I have the register proc and I created the jdled_icon.lrs file with three bitmaps in different sizes like the jdLED.bmp.  However, once the package is installed the icons for the component doesn't look like that as shown in the screen grab.


procedure Register;
begin
  {$I jdled_icon.lrs}
  RegisterComponents('LEDS',[TjdLED]);
end; 

Again it must be something really simple but what?

John

Oh and first two lines of the lrs file are:
LazarusResources.Add('jdLED','BMP',[
  'BM'#246#6#0#0#0#0#0#0'6'#0#0#0'('#0#0#0#24#0#0#0#24#0#0#0#1#0#24#0#0#0#0#0

So correct BMP file was accessed.
« Last Edit: May 04, 2021, 12:11:56 am by jcdammeyer »

jcdammeyer

  • Full Member
  • ***
  • Posts: 205
  • Embedded System Developer
    • Automation Artisans Inc.
Re: TControl and TGraphic Control creation issue
« Reply #17 on: May 04, 2021, 01:24:03 am »
OK.  Bad news but it matches the installed component so that's good news I guess.
I changed this to to move the top corner down.
 SetInitialBounds(50, 50, 130, 234); 
Screen-3.jpg shows that it moved.  The form placed component is still on the far RHS.  All on Windows with Lazarus 2.0.10

Now onto Linux and here is where it still goes south but shows that some sort of parent XY location is not being inherited.

The 15-59-40.png shows the component placed on the far RHS just like on the windows system but the segments are missing.  If I drag it all the way to the left the segments show up as it's dragged across to the 0,0 position.  But for now I'll leave it on the RHS.

Next if I also set initial bounds to 50,50 as in the windows example, the component is rendered in that offset location as far as the TGraphicalControl XY position is concerned but the segments are still anchored at 0,0.  This is shown in the 16-06-56.png screen shot.

So now it's clear that under windows Lazarus does the drawing of polygons relative to the SetInitialBounds(50, 50, 130, 234); statement.  Under Linux  it does it relative to 0,0 and they don't show up unless the TGraphicalControl is in that position.

This is of course far more serious than the wrong ICON BMP placed on the component bar, which by the way, is the same on Linux and Windows.  Probably just doing something wrong there...

So.  Ideas?





jcdammeyer

  • Full Member
  • ***
  • Posts: 205
  • Embedded System Developer
    • Automation Artisans Inc.
Re: TControl and TGraphic Control creation issue
« Reply #18 on: May 04, 2021, 03:17:36 am »
In digging deeper I realized unlike the original Delphi component that I derived this code from, the background wasn't changing.  It used to.  I discovered that I had inadvertently deleted this line in the paint method:
Code: Pascal  [Select][+][-]
  1. -  Canvas.Rectangle(0, 0, Width, Height);
  2.  

That looks better now but unfortunately it didn't fix the issue on the Linux side. 

Diving way down into the GTK code it appears like the DC handle isn't correct.  But I'm not sure why.

jcdammeyer

  • Full Member
  • ***
  • Posts: 205
  • Embedded System Developer
    • Automation Artisans Inc.
Re: TControl and TGraphic Control creation issue
« Reply #19 on: May 04, 2021, 09:02:30 am »
This screen shot is from the Linux Machine.  The two edit boxes show the top left hand corner of each TGraphicalComponent and they match what they've been set at.

But the segments which are polygons are drawn relative to the canvas 0,0 position of the main form rather than the canvas 0,0 of the component objects.

Here's the code that prints out the corners.
Code: Pascal  [Select][+][-]
  1. var aPnt1, aPnt2: TPoint;
  2. begin
  3.   aPnt1 := Point(0, 0);
  4.   aPnt2 := Point(0, 0);
  5.  
  6.   aPnt1 := SevenSegDisplayImage.ClientToParent( aPnt1, Form1 );  // the runtime created component
  7.   Edit1.Text := IntToStr(aPnt1.x) + ' ' + IntToStr(aPnt1.y);
  8.  
  9.   aPnt2 := SevenSegDisplay1.ClientToParent( aPnt2, Form1 );  // The component
  10.   Edit2.Text := IntToStr(aPnt2.x) + ' ' + IntToStr(aPnt2.y);
  11.  

Is this at the point where it's really a bug report and if so where or how would I file it?

wp

  • Hero Member
  • *****
  • Posts: 11853
Re: TControl and TGraphic Control creation issue
« Reply #20 on: May 04, 2021, 11:26:21 am »
I really don't know what's going on here, but when I changed the Left and Top coordinates of the seven-segment component it was moved correctly, but the segments were drawn at inverted positions (i.e. when I said Top = 40 the segments were moved up rather than down). This observation is for Ubuntu 20.10 and LMDE4 (gtk2). On Windows, Cocoa, gtk3  and qt5 everything is correct.

After playing with the component for some time I could find a workaround by re-writing the Canvas.Polygon in a different way:
Code: Pascal  [Select][+][-]
  1. procedure TjdSevenSegDisplay.DrawSegment(s: Byte);
  2. var
  3.   W, H: Double;
  4.   P: Array[0..5] of TPoint;
  5. begin
  6.   W := Width / 20;
  7.   H := Height / 38;
  8.  
  9.   case s of
  10.     0://top
  11.       begin
  12.         P[0] := Point(round(w*2), round(h*1));
  13.         P[1] := Point(round(w*18), round(h*1));
  14.         P[2] := Point(round(w*(18-FSegWidth)), round(h*(1+FSegWidth)));
  15.         P[3] := Point(round(w*(2 +FSegWidth)), round(h*(1+FSegWidth)));
  16.         canvas.Polygon(P, 4);
  17.       end;
  18.     1://upper left
  19.       begin
  20.         P[0] := Point(round(w*1), round(h*2));
  21.         P[1] := Point(round(w*1), round(h*18));
  22.         P[2] := Point(round(w*(1+FSegWidth)), round(h*(18-FSegWidth)));
  23.         P[3] := Point(round(w*(1+FSegWidth)), round(h*(2+FSegWidth)));
  24.         Canvas.Polygon(P, 4);
  25.       end;
  26.     2://upper right
  27.       begin
  28.         P[0] := Point(round(w*19), round(h*2));
  29.         P[1] := Point(round(w*19), round(h*18));
  30.         P[2] := Point(round(w*(19-FSegWidth)), round(h*(18-FSegWidth)));
  31.         P[3] := Point(round(w*(19-FSegWidth)), round(h*(2+FSegWidth)));
  32.         Canvas.Polygon(P, 4);
  33.       end;
  34.     4://lower left
  35.       begin
  36.         P[0] := Point(round(w*1), round(h*20));
  37.         P[1] := Point(round(w*1), round(h*36));
  38.         P[2] := Point(round(w*(1+FSegWidth)), round(h*(36-FSegWidth)));
  39.         P[3] := Point(round(w*(1+FSegWidth)), round(h*(20+FSegWidth)));
  40.         Canvas.Polygon(P, 4);
  41.       end;
  42.  
  43.     5://lower right
  44.       begin
  45.         P[0] := Point(round(w*19), round(h*20));
  46.         P[1] := Point(round(w*19), round(h*36));
  47.         P[2] := Point(round(w*(19-FSegWidth)), round(h*(36-FSegWidth)));
  48.         P[3] := Point(round(w*(19-FSegWidth)), round(h*(20+FSegWidth)));
  49.         canvas.Polygon(P, 4);
  50.       end;
  51.     6://bottom
  52.       begin
  53.         P[0] := Point(round(w*2), round(h*37));
  54.         P[1] := Point(round(w*18), round(h*37));
  55.         P[2] := Point(round(w*(18-FSegWidth)), round(h*(37-FSegWidth)));
  56.         P[3] := Point(round(w*(2+FSegWidth)), round(h*(37-FSegWidth)));
  57.         Canvas.Polygon(P, 4);
  58.       end;
  59.     3://middle
  60.       begin
  61.         P[0] := Point(round(w*2), round(h*19));
  62.         P[1] := Point(round(w*(2+FSegWidth/2)), round(h*(19-FSegWidth/2)));
  63.         P[2] := Point(round(w*(18-FSegWidth/2)), round(h*(19-FSegWidth/2)));
  64.         P[3] := Point(round(w*18), round(h*19));
  65.         P[4] := Point(round(w*(18-FSegWidth/2)), round(h*(19+FSegWidth/2)));
  66.         P[5] := Point(round(w*(2+FSegWidth/2)), round(h*(19+FSegWidth/2)));
  67.         Canvas.Polygon(P, 6);
  68.       end;
  69.   end;
  70. end;
« Last Edit: May 04, 2021, 01:28:25 pm by wp »

wp

  • Hero Member
  • *****
  • Posts: 11853
Re: TControl and TGraphic Control creation issue
« Reply #21 on: May 04, 2021, 02:13:21 pm »
With the following test project I was able to further narrow the issue. The code draws two red rectangles inside a custom control's Paint method. The control is anchored to the right and bottom edges of the form; therefore, the control moves when the window size is changed. Both rectangles are expected to follow the control. But the left rectangle remains at its initial position. It is drawn by the Canvas.Polygon overload using the constant point array as parameter. The right rectangle behaves correctly, it is drawn by the Canvas.Polygon overload which gets the points as parameters.

The left rectangle behaves correctly when the define SHOW_BUG is deactivated - this simply switches the Pen.Style from psClear to psSolid. Therefore, I'd conclude that something is wrong inside the gtk2 widgetset's Polygon routine, when Pen.Style is psClear.

I filed a bug report (https://bugs.freepascal.org/view.php?id=38852).

Code: Pascal  [Select][+][-]
  1. unit unit2;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. {$DEFINE SHOW_BUG}
  6.  
  7. interface
  8.  
  9. uses
  10.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs;
  11.  
  12. type
  13.   TTestControl = class(TGraphicControl)
  14.   protected
  15.     procedure Paint; override;
  16.   end;
  17.  
  18.   { TForm1 }
  19.  
  20.   TForm1 = class(TForm)
  21.     procedure FormCreate(Sender: TObject);
  22.   end;
  23.  
  24. var
  25.   Form1: TForm1;
  26.  
  27. implementation
  28.  
  29. {$R *.lfm}
  30.  
  31. procedure TTestControl.Paint;
  32. var
  33.   P: Array[0..3] of TPoint;
  34. begin
  35.   {$IFDEF SHOW_BUG}
  36.   Canvas.Pen.Style := psClear;
  37.   {$ELSE}
  38.   Canvas.Pen.Style := psSolid;
  39.   {$ENDIF}
  40.   Canvas.Brush.Color := clWhite;
  41.   Canvas.FillRect(0, 0, Width, Height);
  42.  
  43.   Canvas.Brush.Color := clRed;
  44.   // This call is in error
  45.   Canvas.Polygon([Point(20, 20), Point(80, 20), Point(80, 80), Point(20, 80)]);
  46.  
  47.   // This call is correct
  48.   P[0] := Point(80, 20);
  49.   P[1] := Point(140, 20);
  50.   P[2] := Point(140, 80);
  51.   P[3] := Point(80, 80);
  52.   Canvas.Polygon(P, 4);
  53. end;
  54.  
  55. procedure TForm1.FormCreate(Sender: TObject);
  56. begin
  57.   with TTestControl.Create(Self) do
  58.   begin
  59.     SetBounds(0, 20, 180, 210);
  60.     Anchors := [akRight, akBottom];
  61.     Parent := Self;
  62.   end;
  63. end;
  64.  
  65. end.                  
« Last Edit: May 04, 2021, 02:39:25 pm by wp »

jcdammeyer

  • Full Member
  • ***
  • Posts: 205
  • Embedded System Developer
    • Automation Artisans Inc.
Re: TControl and TGraphic Control creation issue
« Reply #22 on: May 05, 2021, 01:32:25 am »
It's going to be a while before I can show the results for the Pi.  My Pi3 power supply had some sort of hiccup and destroyed the linux partition.  Couldn't read it on anything anymore. 

For some reason the Pi4 with the LinuxCNC OS dies halfway through installing fpcupdeluxe.  So I downloaded the latest Pi OS and created two micro SD cards, one for the Pi3 and one for the Pi4.  I've run the batch streams on both.  Just about to install fpcupdeluxe on the Pi3.  Not sure which version to put on the Pi4.

But in either case, thanks WP so much for finding that the compiler is screwing up with passing the TPoint set.  I've attached 3 screen shots to show that not only are the run time 7 segment displays in the correct spot but also the component installed into the IDE now drags the segments around with it on the form.  Took forever to recompile the IDE on the Beagle but once it was done it worked great.

John

Edit:  Added the Pi Screen shot now that that fpcupdeluxe has been installed.  Did forget to click the button to show the display positions but doesn't matter.  One is dynamic, the other placed on the form at design time.
« Last Edit: May 05, 2021, 06:42:57 am by jcdammeyer »

jcdammeyer

  • Full Member
  • ***
  • Posts: 205
  • Embedded System Developer
    • Automation Artisans Inc.
Re: TControl and TGraphic Control creation issue
« Reply #23 on: May 05, 2021, 06:41:39 am »
And what started it all was a time of day clock last summer with the idea that eventually the bit map would be streamed out the SPI port of a Pi or Beagle. The display using not the HDMI screen but a smaller LCD screen.  But with the code done in Lazarus rather than Python or C.

If the check box is ticked the screen blanks after 10 seconds. The Snooze button lights the time up for another 10 seconds.  It uses the dsLEDs library I ported from Delphi.  This will now still need a bit of work since it uses other line drawing that may also not work properly on the Linux side of things.

When the dsLEDs package is fully converted I'll post it here.

jcdammeyer

  • Full Member
  • ***
  • Posts: 205
  • Embedded System Developer
    • Automation Artisans Inc.
Re: TControl and TGraphic Control creation issue
« Reply #24 on: May 06, 2021, 07:10:22 am »
So just a quick update and some code. 

WP had mentioned that using psSolid also solved the problem.  So I put in the {$IFNDEF ALTERNATE_POLYGON} to either use the original list of points passed inside the Polygon() method or else passing the array with the points.

Next I added either psSolid or psClear with the {$IFNDEF to select.

Now the 7 segments are correctly positioned but with a solid line around the polygons which is not what I wanted.  This screen was done on a Pi4.  Just forgot to change the form Title.

Thanks again to WP for finding the problem.  I've attached the source code for anyone who wants to play.

wp

  • Hero Member
  • *****
  • Posts: 11853
Re: TControl and TGraphic Control creation issue
« Reply #25 on: May 06, 2021, 10:54:53 am »
In the meantime Anton Kavalenka posted a patch to my bugreport, and the issue is fixed now in trunk (https://bugs.freepascal.org/view.php?id=38852). If you don't use trunk you can easily modify a single line in one of the gtk2 files of your installation:
  • Open file gtk2winapi.inc from folder lcl/interfaces/gtk2 of your Lazarus installation (Note: there is also a file gtk2winapih.inc which would be wrong...)
  • Find function TGtk2WidgetSet.Polygon, it should begin at around line number 6900.
  • A few lines after the "begin" you'll see this code:
Code: Pascal  [Select][+][-]
  1.   // create the PointsArray, which is a copy of Points moved by the DCOrigin
  2.   // only if needed
  3.   if (DevCtx.IsNullPen and (DevCtx.IsNullBrush or Winding)) then
  4.     PointArray := nil
  • Replace the line with the "if..." by "if DevCtx.IsNullPen and DevCtx.IsNullBrush then" (i.e. remove the "or Winding")
  • Recompile the IDE, and when Lazarus restarts you can use your old code again


jcdammeyer

  • Full Member
  • ***
  • Posts: 205
  • Embedded System Developer
    • Automation Artisans Inc.
Re: TControl and TGraphic Control creation issue
« Reply #26 on: May 06, 2021, 08:55:17 pm »
So far this works on LinuxCNC and the Beaglebone.  Haven't tried it yet on the Pi3 or Pi4.
However it does raise a few questions.
1. What is Winding?  A search shows up the usage of this is poorly or not documented at all.  Like a "if the moon is full" flag.
2. The definition of DevCtx.IsNullPen is in an included file and linkage to the actual function is also obscure.  Does IsNullPen return True if psClear is set for the pen?

The reason I ask is when I was single stepping through the program after WP posted the working version with an initialized array I stumbled into that code in the Polygon method.  In fact when I went to the LinuxCNC system to add this new fix that removes winding,  the file was already loaded and the cursor was right at that point.  So I'd gotten to the point where it was in fault.

But I got lost for the reasons stated above.  Couldn't find additional information and there wasn't any documentation that explained why  it was testing for this winding flag.  (Which BTW, was TRUE when stopped at this breakpoint).

Sure glad the problem is fixed.  I'll start a new thread on the component icon issue.

So again.  Thank you, thank you, thank you.
John

jcdammeyer

  • Full Member
  • ***
  • Posts: 205
  • Embedded System Developer
    • Automation Artisans Inc.
Re: TControl and TGraphic Control creation issue
« Reply #27 on: May 06, 2021, 10:08:59 pm »
One other question.  Using fcpupdeluxe on a new device, what is selected to get this bug fix without editing the file again?

Or is this better asked on this thread?
https://forum.lazarus.freepascal.org/index.php?topic=46438.new;topicseen#new

wp

  • Hero Member
  • *****
  • Posts: 11853
Re: TControl and TGraphic Control creation issue
« Reply #28 on: May 06, 2021, 10:20:10 pm »
1. What is Winding?  A search shows up the usage of this is poorly or not documented at all. 
It is mentioned in https://wiki.lazarus.freepascal.org/Graphics_-_Working_with_TCanvas#Self-overlapping_polygons or in https://lazarus-ccr.sourceforge.io/docs/lcl/graphics/tcanvas.polygon.html:
Quote
Winding determines how the polygon is filled. When Winding is True, Polygon fills the shape using the Winding fill algorithm.
When Winding is False, Polygon uses the even-odd (alternative) fill algorithm.
But you may have to ask the internet to learn about these algorithms. It's about determining whether a point is inside a closed polygon or outside. Without going into detail, the effect of the winding parameter on a polygon fill can be seen in the attached demo project.

2. The definition of DevCtx.IsNullPen is in an included file and linkage to the actual function is also obscure.  Does IsNullPen return True if psClear is set for the pen?
Don't let these details confuse you. They are deep inside the heart of the gtk2 widgetset, and normally not needed by the application developer.

wp

  • Hero Member
  • *****
  • Posts: 11853
Re: TControl and TGraphic Control creation issue
« Reply #29 on: May 06, 2021, 10:37:17 pm »
Using fcpupdeluxe on a new device, what is selected to get this bug fix without editing the file again?
In the Lazarus Version listbox select the option "trunk" - this is the development version but you should be aware that it is not as stable as the fixes or numbered release versions. The patch has been put onto the merge request list for the Fixes branch (https://wiki.lazarus.freepascal.org/Lazarus_2.0_fixes_branch#Fixes_for_2.0.14), so after some time you will find it also in the "Fixes" item of the listbox.

 

TinyPortal © 2005-2018