Recent

Author Topic: Setting TPairSplitter position at runtime  (Read 6991 times)

MarkMLl

  • Hero Member
  • *****
  • Posts: 6683
Setting TPairSplitter position at runtime
« on: September 12, 2019, 10:28:05 pm »
I'm sure this is an FAQ but so far I've not found the magic search term.

I'm trying to restore the size of a form and the position of a couple of TPairSplitters (containing several layers of nested panels etc.) as preparation for adjusting things so that one pane has the right size for a cut-and-paste.

Restoring the form to the size it had at program startup is trivial, but how do I adjust the pairsplitters? The description of the position property implies that whilst it's not read-only the way to change position is by a drag operation... surely it can also be done by code?

MarkMLl

MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

wp

  • Hero Member
  • *****
  • Posts: 11912
Re: Setting TPairSplitter position at runtime
« Reply #1 on: September 12, 2019, 11:17:24 pm »
Look into the sources (CTRL-click on TPairSplitter to open the source file in which TPairSplitter is implemented). You'll see a property "Position" there, it is read-write and seems to be what your are looking for.

Try attached demo to see that it is working.

However, I do not use use TPairSplitter normally, only regular splitters because I know them from Delphi. In a recent project I used Ondrej's TOMultiPanel (http://www.kluug.net/omultipanel.php, recent source at https://sourceforge.net/p/omultipanel/code/HEAD/tree/): it is similar to a TPairSplitter but much more versatile. Highly recommended for complex flexible layouts!

jamie

  • Hero Member
  • *****
  • Posts: 6129
Re: Setting TPairSplitter position at runtime
« Reply #2 on: September 12, 2019, 11:40:29 pm »
I like using the anchor editor for splitters, they seem to work better..
The only true wisdom is knowing you know nothing

wp

  • Hero Member
  • *****
  • Posts: 11912
Re: Setting TPairSplitter position at runtime
« Reply #3 on: September 13, 2019, 12:22:43 am »
I never managed to get a functional splitter using the AnchorEditor (i.e. not using the Align property). Can you explain?

jamie

  • Hero Member
  • *****
  • Posts: 6129
Re: Setting TPairSplitter position at runtime
« Reply #4 on: September 13, 2019, 01:26:10 am »
all alignment for the splitter must be off, it does not work well at all.

Personally I think it should be off by default in the OI because it causes design issues.

 That being said, I then use the anchor editor where as I have for example the controls beside it anchor to the splitter and the controls also need to have align off for this to work and so all you need to do is position the splitter and the adjacent controls will follow it as long as you have them anchored to the splitter.
 
 So I've found that it is required to disable the alignment on controls you want to stay with the splitter, this goes for the splitter too.

 When refreshing the form the controls follow the splitter.
The Controls also need to be anchored to the Form or what ever is on the other side of them.
 
 It works well for using the anchor editor..

 years ago before this option came along it was very tricky to get this working because I had to do all of this in the ONSize event which then would retrigger other events and so on.

The only true wisdom is knowing you know nothing

jamie

  • Hero Member
  • *****
  • Posts: 6129
Re: Setting TPairSplitter position at runtime
« Reply #5 on: September 13, 2019, 01:59:51 am »
I wanted to add, if you are trying this with the TpairSplitter, this is slightly a different animal..

 It's tricking getting at the anchor editor, I have to use the OI property panel and click there to get the dialog to come up on the correct part of the control.

 It gets messy especially when you have controls inside the pair splitter, that is when you can use the anchor editor directly to keep this aligned also its hard to use the form designer to move it around I need to use the property OI and set the values because you can't simply get the mouse to grab onto the base of the control.

 I normally use the standard Tsplitter.
The only true wisdom is knowing you know nothing

wp

  • Hero Member
  • *****
  • Posts: 11912
Re: Setting TPairSplitter position at runtime
« Reply #6 on: September 13, 2019, 10:47:44 am »
Thanks for your response, jamie. Got it working finally. For others who had the same problem I am writing down step-by-step instructions (see also attached demo):
  • Add two panels and a splitter.
  • Set Align = alNone for the splitter, the panels have this setting by default.
  • The next steps are done with the Anchor Editor:
    • Anchor the top and bottom sides of the panels and the splitter to the corresponding sides of the form.
    • Select the first panel and anchor its left side to the left side of the form and its right side to the left side of the splitter.
    • Select the second panel and anchor its right side to the right side of the form and its left side to the right side of the splitter.
    • The left and right sides of the splitter must not be anchored (as seen from the splitter itself) because this would fix the position of the splitter and make it not movable.
  • Compile and run --> working!

jamie

  • Hero Member
  • *****
  • Posts: 6129
Re: Setting TPairSplitter position at runtime
« Reply #7 on: September 13, 2019, 06:36:46 pm »
That is a very clean layout thanks for the writeup...

 Also, I think it would be prudent if maybe someone  could get the default alignment set to alNone on the next release because this really bites it hard..
« Last Edit: September 13, 2019, 06:47:17 pm by jamie »
The only true wisdom is knowing you know nothing

wp

  • Hero Member
  • *****
  • Posts: 11912
Re: Setting TPairSplitter position at runtime
« Reply #8 on: September 13, 2019, 06:53:49 pm »
I guess it conflicts with Delphi compatibility. Delphi has TSplitter.Align = alLeft by default. Thus, when a Delphi form with a splitter is loaded into Lazarus the layout will be broken because the default value is not contained in the dfm/lfm file.

I added the steps to the wiki article (https://wiki.freepascal.org/Anchor_Sides#Example_4).
« Last Edit: September 13, 2019, 07:35:46 pm by wp »

MarkMLl

  • Hero Member
  • *****
  • Posts: 6683
Re: Setting TPairSplitter position at runtime
« Reply #9 on: September 13, 2019, 07:26:57 pm »
Try attached demo to see that it is working.

You, sir, have the luck of the Devil :-)

Change your code to look like

Code: [Select]
procedure TForm1.ReadFromIni;
...
    PairSplitter1.Position := ini.ReadInteger('PairSplitter', 'Position', PairSplitter1.Width div 2);

and it won't work any more.

What appears to be happening is that manually dragging the PairSplitter doesn't update its Position property until the UpdatePosition method is called. In addition, the first thing that happens when Position is written is that the existing and new values are compared, and if they match the method exits.

Your ini.ReadInteger() was reading Position to get a default, and this was invisibly calling UpdatePosition to set FPosition to the actual position. If you don't do that then Position still has the value from the last time the property was read, and trying to set it will do nothing. Or words to that effect :-)

MarkMLl

MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

wp

  • Hero Member
  • *****
  • Posts: 11912
Re: Setting TPairSplitter position at runtime
« Reply #10 on: September 13, 2019, 07:49:41 pm »
Change your code to look like

Code: [Select]
procedure TForm1.ReadFromIni;
...
    PairSplitter1.Position := ini.ReadInteger('PairSplitter', 'Position', PairSplitter1.Width div 2);

and it won't work any more.
Well, it is working for me also with your modification...

Since widgetset-dependent code is involved in the TPairSplitter: What is your widgetset? I am on Windows.

MarkMLl

  • Hero Member
  • *****
  • Posts: 6683
Re: Setting TPairSplitter position at runtime
« Reply #11 on: September 13, 2019, 08:01:11 pm »
Well, it is working for me also with your modification...

Since widgetset-dependent code is involved in the TPairSplitter: What is your widgetset? I am on Windows.

Gtk2. Windows might not have the "optimisation" that rejects apparently-useless updates, or might update the Position property without having to be reminded... either of those would fix it.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

jamie

  • Hero Member
  • *****
  • Posts: 6129
Re: Setting TPairSplitter position at runtime
« Reply #12 on: September 13, 2019, 08:47:38 pm »
That makes no sense really, did you call the UPDATE or repaint after setting from INiFile?
The only true wisdom is knowing you know nothing

MarkMLl

  • Hero Member
  • *****
  • Posts: 6683
Re: Setting TPairSplitter position at runtime
« Reply #13 on: September 13, 2019, 09:55:07 pm »
That makes no sense really, did you call the UPDATE or repaint after setting from INiFile?

What I said: UpdatePosition. The FPosition field (hence Position property) appears to not track manual changes, at least on gtk2.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

wp

  • Hero Member
  • *****
  • Posts: 11912
Re: Setting TPairSplitter position at runtime
« Reply #14 on: September 13, 2019, 10:30:34 pm »
Now I also tried gtk2 and qt: No problems either (it's a bit hard here to hit the splitter, though).

 

TinyPortal © 2005-2018