Recent

Author Topic: Trying to create a dynamic form  (Read 5435 times)

jamie

  • Hero Member
  • *****
  • Posts: 6798
Re: Trying to create a dynamic form
« Reply #15 on: February 18, 2024, 08:11:24 pm »
I don't know what your redraw issues are all about, it worked fine over in when parented.

 In any case, you can set the border icons or border to none etc.
The only true wisdom is knowing you know nothing

fxeconomist

  • New Member
  • *
  • Posts: 48
Re: Trying to create a dynamic form
« Reply #16 on: February 19, 2024, 11:31:09 am »
Now I've run into another snag.

The code kinda works, only if I call it from the main window, some time after it draws. I actually have a timer object for this job, for other complications, but it does do the work...

Code: Pascal  [Select][+][-]
  1. procedure CreateDebugWindow;
  2. begin
  3.    if DebugWindowEnabled=true then
  4.       if DebugWindow=nil then begin
  5.       DebugWindow:=TForm.Create(nil);
  6.       DebugWindow.Parent:=nil;
  7.       DebugWindow.SetBounds(100, 100, 800, 600);
  8.       DebugWindow.BorderStyle := bsToolWindow;
  9.       DebugWindow.Caption:='Debug Window';
  10.       DebugWindowShape:=TShape.Create(nil);
  11.       DebugWindowShape.Parent:=DebugWindow;
  12.       DebugWindowShape.Top:=1;
  13.       DebugWindowShape.left:=1;
  14.       DebugWindowShape.Width:=DebugWindow.Width;
  15.       DebugWindowShape.Height:=DebugWindow.Height;
  16.       DebugWindowShape.Brush.Color:=clBlack;
  17.       DebugWindowShape.Brush.Style:=bsSolid;
  18.       DebugWindowShape.Canvas.Font.Name:='Courier New';
  19.       DebugWindowShape.Canvas.Font.Size:=12;
  20.       DebugWindowShape.Canvas.Pen.Color:=clWhite;
  21.       DebugWindowShape.Canvas.Pen.Style:=psSolid;
  22.    end;
  23. end;
  24.  
  25.  
  26. procedure ShowDebugWindow;
  27. begin
  28.   CreateDebugWindow();
  29.   if DebugWindowEnabled=true then begin
  30.      DebugWindow.Show();
  31.      //DebugWindow.SetBounds(100, 100, 600, 800);
  32.      DebugWindowShape.Canvas.TextOut(10,10,'ABCD');
  33.      DebugWindowShape.Canvas.Line(10,10,300,300);
  34.      DebugWindow.Refresh();
  35.   end;
  36. end;                          

So it creates the window on top, it attaches the Shape object inside, and it makes it black, as per the Brush.

From that point nothing else works. There is no line drawn, and no text for that matter. I tried also without setting the Pen, with the defaults.
That doesn't work either.

alpine

  • Hero Member
  • *****
  • Posts: 1343
Re: Trying to create a dynamic form
« Reply #17 on: February 19, 2024, 11:42:28 am »

So it creates the window on top, it attaches the Shape object inside, and it makes it black, as per the Brush.

From that point nothing else works. There is no line drawn, and no text for that matter. I tried also without setting the Pen, with the defaults.
That doesn't work either.
You can't draw that way on a canvas. You must put all your drawing code into DebugWindowShape.OnPaint handler or to override the TGraphicControl.Paint method.
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

fxeconomist

  • New Member
  • *
  • Posts: 48
Re: Trying to create a dynamic form
« Reply #18 on: February 19, 2024, 12:10:27 pm »

So it creates the window on top, it attaches the Shape object inside, and it makes it black, as per the Brush.

From that point nothing else works. There is no line drawn, and no text for that matter. I tried also without setting the Pen, with the defaults.
That doesn't work either.
You can't draw that way on a canvas. You must put all your drawing code into DebugWindowShape.OnPaint handler or to override the TGraphicControl.Paint method.

What ? I have two TShape objects inside my main form, and I actually draw that way on them.
Yes there is a problem on program init - hence the trick with the timer object - but it actualy does the job. Without the timer, the drawing gets kinda convoluted.

Before using the timer, the Clear method of the Canvas was bypassed at the second call. So, the program was doing the main drawing. I pushed a button (have buttons to rotate the thing in 3d), and then it was redrawing over, without Clear. Any subsequent button push was doing the Clear correctly.

I mean it's a bit absurd. Imagine you start a game and you have to push a "Start" button to get to the main splash screen. Shown doesn't exist in Lazarus, so I have to use a timer to actually wait for the window to be completed.

But it does the job right, of course if it gets finished in 500ms.

And now I added the DebugWindow initialization straight in the code of the timer.

This is how this fabled section looks like. It took me like two weeks to get it to work properly.

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Timer1Timer(Sender: TObject); //OnTimer
  2. begin
  3.   Timer1.Enabled:=false;
  4.   DrawAll();//first drawing
  5.   EnableControls(true);
  6.  
  7.   ShowDebugWindow();
  8. end;
  9.  
  10.  
  11. procedure TForm1.FormActivate(Sender: TObject);
  12. begin
  13.   //needed here TO PRESERVE first drawing made from Timer event, otherwise IT GETS WIPED
  14.   DrawAll();
  15. end;            
  16.  


rvk

  • Hero Member
  • *****
  • Posts: 6658
Re: Trying to create a dynamic form
« Reply #19 on: February 19, 2024, 12:45:00 pm »
I mean it's a bit absurd. Imagine you start a game and you have to push a "Start" button to get to the main splash screen. Shown doesn't exist in Lazarus, so I have to use a timer to actually wait for the window to be completed.
That's why you should use the OnPaint. It paints when needed. Now with the TTimer you actually might paint when not needed (plus the timer could be too late to paint resulting in delay etc.).

Sure. if it works for you then fine... but this is not the correct way to do it in Object Pascal.

fxeconomist

  • New Member
  • *
  • Posts: 48
Re: Trying to create a dynamic form
« Reply #20 on: February 19, 2024, 01:01:14 pm »
I mean it's a bit absurd. Imagine you start a game and you have to push a "Start" button to get to the main splash screen. Shown doesn't exist in Lazarus, so I have to use a timer to actually wait for the window to be completed.
That's why you should use the OnPaint. It paints when needed. Now with the TTimer you actually might paint when not needed (plus the timer could be too late to paint resulting in delay etc.).

Sure. if it works for you then fine... but this is not the correct way to do it in Object Pascal.

I didn't even know about OnPaint(). Everything I did, I saw it probably in a tutorial before. Perhaps I'm antiquated, but in my mind, Paint() is something that Windows does when it actually paints a window. I'll have to give it a try.

alpine

  • Hero Member
  • *****
  • Posts: 1343
Re: Trying to create a dynamic form
« Reply #21 on: February 19, 2024, 01:02:19 pm »
@fxeconomist
You'll never succeed to do it right unless you familiarize yourself with the way the GUI toolkits work.
All painting is done on demand via paint messages and invoking the Paint method (the Toolkit does that). You can consider that Canvas property is mostly valid into the body of Paint method and the OnPaint event handler, which is invoked by the former. There you must put your drawing code.
« Last Edit: February 19, 2024, 01:06:34 pm by alpine »
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

rvk

  • Hero Member
  • *****
  • Posts: 6658
Re: Trying to create a dynamic form
« Reply #22 on: February 19, 2024, 01:08:34 pm »
I didn't even know about OnPaint(). Everything I did, I saw it probably in a tutorial before. Perhaps I'm antiquated, but in my mind, Paint() is something that Windows does when it actually paints a window. I'll have to give it a try.
I'm also not sure why you used TShape ??
Is there a reason for it?

Quote
TShape tshape.png is a component that creates a shape (triangle, circle or square) on the surface of its parent (such as a TForm). It is a TGraphicControl descendant and is available under the Additional tab of the Component Palette.

If you don't want to redraw each time when needed and want Lazarus to handle that, you should use something like TImage and paint to its bitmap. That will be saved (in the bitmap) and redrawn on command.


Thaddy

  • Hero Member
  • *****
  • Posts: 16520
  • Kallstadt seems a good place to evict Trump to.
Re: Trying to create a dynamic form
« Reply #23 on: February 19, 2024, 01:52:49 pm »
Or use BeginFormUpdate/EndFormUpdate with your setup code in between.
Btw for your use you get the fastest experience by overriding AfterConstruction and perform all setup there. This works after the form is completely initialized and just before the first formshow.
You do not have to call afterconstruction. It will be called automatically. Just override it.

This is a bit underused, everybody and their old boots want to use the formcreate event. But overriding AfterConstruction is much, much faster. Why? no event loop....No repaints..
« Last Edit: February 19, 2024, 03:11:52 pm by Thaddy »
But I am sure they don't want the Trumps back...

JWBokx

  • Newbie
  • Posts: 3
Re: Trying to create a dynamic form
« Reply #24 on: February 19, 2024, 03:32:49 pm »
I'm new here, and are more a Delphi man until now.

But in the code in the first post in the initialsization you first set the parent, but there is no debugwindow yet.
It's only created in the show method and only if the gloabal var is true.
So the parent is set on a non existing form.

Thaddy

  • Hero Member
  • *****
  • Posts: 16520
  • Kallstadt seems a good place to evict Trump to.
Re: Trying to create a dynamic form
« Reply #25 on: February 19, 2024, 04:31:23 pm »
That is well observed.
Two remarks:
1. The owner can be nil, that in itself is legal
2. He may set the owner to the Application instance, which is already availabe, but maybe even the main form is enough.
« Last Edit: February 19, 2024, 05:31:36 pm by Thaddy »
But I am sure they don't want the Trumps back...

fxeconomist

  • New Member
  • *
  • Posts: 48
Re: Trying to create a dynamic form
« Reply #26 on: February 19, 2024, 06:09:02 pm »
I'm new here, and are more a Delphi man until now.

But in the code in the first post in the initialsization you first set the parent, but there is no debugwindow yet.
It's only created in the show method and only if the gloabal var is true.
So the parent is set on a non existing form.

Oh I get it, it was the initialization sequence of the form unit, but the form was probably not created yet... Hmm...

fxeconomist

  • New Member
  • *
  • Posts: 48
Re: Trying to create a dynamic form
« Reply #27 on: February 19, 2024, 06:12:17 pm »
I didn't even know about OnPaint(). Everything I did, I saw it probably in a tutorial before. Perhaps I'm antiquated, but in my mind, Paint() is something that Windows does when it actually paints a window. I'll have to give it a try.
I'm also not sure why you used TShape ??
Is there a reason for it?

Quote
TShape tshape.png is a component that creates a shape (triangle, circle or square) on the surface of its parent (such as a TForm). It is a TGraphicControl descendant and is available under the Additional tab of the Component Palette.

If you don't want to redraw each time when needed and want Lazarus to handle that, you should use something like TImage and paint to its bitmap. That will be saved (in the bitmap) and redrawn on command.

Well, the logo had some geometric shapes on it.

But now, what do I do now ?

I can write in the TShape of the DebugWindow, but in order to scroll, I will have to copy and paste areas of the Shape. Can this be done better with a TImage ?

rvk

  • Hero Member
  • *****
  • Posts: 6658
Re: Trying to create a dynamic form
« Reply #28 on: February 19, 2024, 06:27:26 pm »
I can write in the TShape of the DebugWindow, but in order to scroll, I will have to copy and paste areas of the Shape. Can this be done better with a TImage ?
Yes, if you don't want to do it in a TShape.OnPaint event, you need to do it on a persistent canvas.

The canvas of TShape isn't persistent. Each time it needs to be redrawn (which Windows decides and definitely happens each time you move the complete form) the original shape is drawn which looses all you own drawn things.

That's why you need to draw those things in the Onpaint of TShape so they also get drawn when needed.

The other option is to use a persistent canvas like the one from a TBitmap (for instance in a TImage). In that case your drawing will be fine on the bitmap and stored there. Each time the bitmap needs to be redrawn, it's automatically take from there.

But do note, that is you want to change some text, you'll need to repaint that entire area. Otherwise you might end up with text over text.

But... Would it be better to just tell us what this is for?
If it's a debug window you might be better of just using a TMemo on a TForm with summer extra elements like TLabel etc. Building a form in code like that might be more suitable for a debugwindow then drawing on a canvas.

Or do you have any other special need for it??

KodeZwerg

  • Hero Member
  • *****
  • Posts: 2269
  • Fifty shades of code.
    • Delphi & FreePascal
Re: Trying to create a dynamic form
« Reply #29 on: February 19, 2024, 08:09:03 pm »
Usual a logo is an Image stored in the resource section of a binary so its available to all forms via resource-stream and easier to keep unified/update.
For a "DebugWindow" I suggest that you start using logging and in that "DebugWindow" put all those lines of log into a read-only TMemo or similar.
Best would be to show us an Image of what you want to achieve as of right now more and more comes into that was not mentioned in first post.
« Last Edit: Tomorrow at 31:76:97 xm by KodeZwerg »

 

TinyPortal © 2005-2018