hv has asked for the wisdom of the Perl Monks concerning the following question:
I am very new to Tk - and to anything graphical in general - so I may well be missing fundamentals.
I'm trying to create a view showing a fragment of a larger world (A), with a pane below for control options (C), and a pane to the right showing details of an element in the world (B):
+-------+---+
| | |
| A | B |
| | |
+-------+---+
| C |
+-----------+
I'm using a horizontal Panedwindow for A, B, and a vertical Panedwindow for A+B, C, so the user can control the width of B and the height of C. When the window is resized, I want the width of B and height of C to stay constant, and the primary window A to shrink or grow as needed, hopefully with some event I can bind to update its contents. However the opposite is happening: A stays constant, and the other two resize.
I suspect this is the nature of a Panedwindow: if I swap the order I add A and B to the upper pane, for example, the size of B stays fixed on resizing (but it's now on the left). However I don't see anything in the docs for Panedwindow to control this, nor do I see in the code how it handles resizing events. Can someone suggest how to achieve the effect I want?
Update: as pointed out by choroba, this is the nature of a Panedwindow. So can someone point to how that is implemented, so I can create a variant of a different nature?
Another update: in Tk-8.5, panes in a Panedwindow acquired a new stretch attribute that controls how new space is allocated among them. 8.5 also includes ttk, which has its own variant of Panedwindow; this one lets you specify a weight attribute on panes for even finer-grained control. Current Perl-Tk is based on Tk-8.4, so I guess I need to go bug Slaven. I did this in issue 75, which got a comment from chrstphrchvz.
More: tybalt89++ offered a solution in Re: Controlling resize of Tk::Panedwindow which looks to do exactly what I want; I'll be going with that for now. An Anonymous monk looking a lot like zentara also pointed me at a couple of alternative Panedwindow implementations in Re: Controlling resize of Tk::Panedwindow (IDELayout IDEpanedwindow), but the one of those I looked at seems quite buggy. kcott also offered a decent cut-down solution in Re: Controlling resize of Tk::Panedwindow if I didn't mind losing the user-controllable aspect of paned windows.
Hugo
#!perl
use strict;
use warnings;
use Tk;
my $main_window = MainWindow->new;
my $top_container = $main_window->Panedwindow(-orient => 'vertical');
$top_container->pack(
-side => 'top',
-expand => 'yes',
-fill => 'both',
-padx => '2m',
-pady => '2',
);
my $world_container = $top_container->Panedwindow(-orient => 'horizont
+al');
$world_container->pack(
-side => 'top',
-expand => 'yes',
-fill => 'both',
-padx => '2',
-pady => '2m',
);
$top_container->add($world_container);
my $world_view = $world_container->Canvas();
$world_view->pack(
-side => 'left',
-fill => 'both',
-expand => 1,
);
$world_container->add($world_view);
my $entity_view = $world_container->Frame();
$entity_view->pack(
-side => 'right',
-fill => 'y',
-expand => 0,
);
$world_container->add($entity_view);
my $control_view = $top_container->Frame;
$control_view->pack(
-side => 'bottom',
-fill => 'x',
-expand => 0,
);
$top_container->add($control_view);
my $quit_button = $control_view->Button(
-text => 'Quit',
-command => sub { $main_window->destroy },
);
$quit_button->pack(
-side => 'right',
-expand => 'no',
-pady => 2,
);
Tk::MainLoop();
Re: Resizing paned Tk::Canvas
by choroba (Cardinal) on Mar 01, 2021 at 19:13 UTC
|
The documentation says:
> When a pane is resized from outside (eg, it is packed to expand and fill,
and the containing toplevel is resized), space is added to the final
(rightmost or bottommost) pane in the window.
map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
| [reply] [d/l] |
|
| [reply] |
Re: Resizing paned Tk::Canvas
by LanX (Saint) on Mar 01, 2021 at 19:18 UTC
|
Hi
I'm no Tk expert and don't know any better way, but I found this in the original TclTk documentation
RESIZING PANES
When a pane is resized from outside (e.g. it is packed to expand and fill, and the containing toplevel is resized), space is added to the final (rightmost or bottommost) pane in the window.
So I tried to change the order of panes in a way that your "world" pane A was at the lower right and resizing worked as intended.
+-----------+
| C |
+---+-------+
| | |
| B | A |
| | |
+---+-------+
I hope this workaround suites you! :)
| [reply] [d/l] |
Re: Controlling resize of Tk::Panedwindow
by tybalt89 (Monsignor) on Mar 03, 2021 at 01:36 UTC
|
#!/usr/bin/perl
use strict;
use warnings;
use Tk;
use Tk::Adjuster;
use Tk::Pane;
my $mw = MainWindow->new;
my $C = $mw->Frame(-bg => 'red', -width => 200, -height => 200,
)->pack(-side => 'bottom', -expand => 0, -fill => 'x');
$mw->Adjuster()->packAfter($C, -side => 'bottom');
my $B = $mw->Scrolled(Frame => -scrollbars => 'osoe', -sticky => 'nsew
+',
-bg => 'green', -width => 100, -height => 200,
)->pack(-side => 'right', -expand => 0, -fill => 'y');
$mw->Adjuster()->packAfter($B, -side => 'right');
$mw->Frame(-bg => 'blue', -width => 200, -height => 200,
)->pack(-expand => 1, -fill => 'both');
$C->Button(-text => 'Quit', -command => sub {$mw->destroy},
)->pack(-side => 'right');
$C->Button(-text => $_)->pack(-side => 'left') for qw( one two three f
+our);
$B->Label(-text => $_)->pack(-fill => 'x') for 'Element Properties',
qw( one two three four five six seven eight nine ten);
MainLoop;
| [reply] [d/l] |
|
| [reply] |
Re: Controlling resize of Tk::Panedwindow
by Limbic~Region (Chancellor) on Mar 01, 2021 at 20:48 UTC
|
hv,
I no longer code (Perl or otherwise) nor hang out in the Monastery. Nostalgia on the other hand has me periodically checking in. Back in the day, I considered zentara the resident expert on Tk and gtk2. Not sure if that's still true or not but I figured I would share since you have helped me on more than one occasion over the years.
| [reply] |
|
| [reply] |
|
| [reply] |
Re: Controlling resize of Tk::Panedwindow
by chrstphrchvz (Scribe) on Mar 02, 2021 at 23:35 UTC
|
For reference, the thread author opened an issue at the Perl/Tk GitHub repository: https://github.com/eserte/perl-tk/issues/75
While incorporating Tcl/Tk 8.5+ or Ttk into Perl/Tk continues to seem unlikely, I think backporting -stretch could be possible; will comment further on the GitHub issue.
| [reply] |
|
| [reply] |
|
| [reply] |
|
Current Tcl::pTk and Tkx maintainer here. As I previously wrote: if the program in question is indeed an existing Perl/Tk program, then I agree trying Tcl::pTk(::TkHijack) is a much better choice than rewriting for Tkx. Tcl::Tk or Tcl::pTk might also be preferable for those already familiar with Perl/Tk but not Tkx. But if the program is instead being written from scratch by someone not already familiar with Perl/Tk, then I do think they could be better off following TkDocs.com tutorials for Tkx.
And if someone still prefers using Perl/Tk, e.g. because of its relative ease of installation over Tcl/Tk wrappers like Tkx and Tcl::pTk, then backporting features to Perl/Tk can be investigated/attempted.
| [reply] |
Re: Controlling resize of Tk::Panedwindow
by kcott (Archbishop) on Mar 02, 2021 at 07:47 UTC
|
#!/usr/bin/env perl
use strict;
use warnings;
use Tk;
my $mw = MainWindow::->new();
my $fAB = $mw->Frame()->pack(-fill => 'both', -expand => 1);
my $fA = $fAB->Frame(-bg => '#ff0000'
)->pack(-side => 'left', -fill => 'both', -expand => 1);
my $fB = $fAB->Frame(-bg => '#ffff00'
)->pack(-side => 'left', -fill => 'y');
my $fC = $mw->Frame(-bg => '#0000ff'
)->pack(-fill => 'x');
$fA->Label(-text => 'A')->pack();
$fB->Label(-text => 'B')->pack();
$fC->Label(-text => 'C')->pack();
MainLoop;
I've colour-coded the A,B and C frames so that the effects of resizing are more obvious.
| [reply] [d/l] |
|
Thanks, I'll keep that approach in mind as a last resort; I'd prefer to keep the sliders that permit manual readjustment of the pane sizes, but maybe I could live without them if it gets too tricky (and if I can be confident of ensuring the subsidiary panes are always at least big enough to reach their own varying content).
| [reply] |
|
| [reply] |
Re: Controlling resize of Tk::Panedwindow (IDELayout IDEpanedwindow)
by Anonymous Monk on Mar 02, 2021 at 02:49 UTC
|
#!/usr/bin/perl --
use strict;
use warnings;
use Tk;
use Tk::IDEpanedwindow;
my $main_window = MainWindow->new( -bg => 'black' );
my $top_container = $main_window->IDEpanedwindow(
qw/-orient vertical -sashpad 1
-sashwidth 3 -sashrelief groove -bg red/);
$top_container->pack(
-side => 'top',
-expand => 'yes',
-fill => 'both',
-padx => '2m',
-pady => '2',
);
my $world_container = $top_container->IDEpanedwindow(
qw/-orient horizontal -sashpad 1
-sashwidth 3 -sashrelief groove -bg green /
);
$world_container->pack(
-side => 'top',
-expand => 'yes',
-fill => 'both',
-padx => '2',
-pady => '2m',
);
$top_container->add( $world_container, -expandfactor, 1, );
my $world_view = $world_container->Canvas( -bg => 'orange' );
$world_view->pack(
-side => 'left',
-fill => 'both',
-expand => 1,
);
## sometimes factor 3 is too much, sometimes not enough
# $world_container->add($world_view , -expandfactor,3 );
$world_container->add( $world_view, -expandfactor, 10 );
my $entity_view = $world_container->Frame( -bg => 'blue', );
$entity_view->pack(
-side => 'right',
-fill => 'y',
-expand => 0,
);
$world_container->add( $entity_view,
-expandfactor, 1, -minsize => 100 ); # SASH limits);
my $control_view = $top_container->Frame( -bg => 'yellow', );
$control_view->pack(
-side => 'bottom',
-fill => 'x',
-expand => 0,
);
$top_container->add( $control_view,
-expandfactor, 1, -minsize => 60 ); # SASH limits);
my $quit_button = $control_view->Button(
-text => 'Quit',
# -command => sub { $main_window->destroy },
# -command => ['destroy', $main_window ],
-command => 'exit',
);
$quit_button->pack(
-side => 'right',
-expand => 'no',
-pady => 2,
);
$main_window->WidgetDump if @ARGV;
Tk::MainLoop();
Panedwindow provides a minsize sash resizing limit, but IDEpanedwindow doesnt
Another thing to try is https://www.tcl.tk/man/tcl8.6/TkCmd/ttk_panedwindow.htm somehow, as it has a "weight" option,
which you can try by way of https://metacpan.org/pod/Tcl::pTk
but to me it seems to be similarly funky as expandfactors
Both can be made to do what you want but its fiddly , factors need to adjusted (factored) based on window size, and minimum sizes pre-set and enforced ... I leave that up to you
#!/usr/bin/perl --
use strict;
use warnings;
use Tcl::pTk::TkHijack;
use Tk;
my $main_window = MainWindow->new( -bg => 'black' );
my $int = $main_window->interp;
# Get the intepreter that was created in the MainWindow call
$int->Eval(<<'__TCL__');
ttk::panedwindow .top_container -orient vertical
ttk::panedwindow .world_container -orient horizontal -height 100
ttk::style configure . -background black
## fail
ttk::style configure .top_container -background red
ttk::style configure .world_container -background green
__TCL__
my $top_container = $int->widget('.top_container');
# fail #~ $top_container->configure(qw/-background red /);
my $world_container = $int->widget('.world_container');
$top_container->pack(
-side => 'top',
-expand => 'yes',
-fill => 'both',
-padx => '2m',
-pady => '2',
);
$world_container->pack(
-side => 'top',
-expand => 'yes',
-fill => 'both',
-padx => '2',
-pady => '2m',
);
$top_container->add( $world_container, -weight, 2 );
my $world_view = $world_container->Canvas( -bg => 'orange' );
$world_view->pack(
-side => 'left',
-fill => 'both',
-expand => 1,
);
$world_container->add( $world_view, -weight, 30 );
my $entity_view = $world_container->Frame( -bg => 'blue', );
$entity_view->pack(
-side => 'right',
-fill => 'y',
-expand => 0,
);
$world_container->add( $entity_view, -weight, 2 );
my $control_view = $top_container->Frame( -bg => 'yellow', );
$control_view->pack(
-side => 'bottom',
-fill => 'x',
-expand => 0,
);
$top_container->add( $control_view, -weight, 2 );
my $quit_button = $control_view->Button(
-text => 'Quit',
-command => [ 'destroy', $main_window ],
);
$quit_button->pack(
-side => 'right',
-expand => 'no',
-pady => 2,
);
Tk::MainLoop();
*) the labels ought to match the variable names (A B C does not match world_view...), its like labeling a red window orange
| [reply] [d/l] [select] |
|
Current Tk::IDElayout and Tcl::pTk maintainer here. If one can get their program working with Tcl::pTk, I would probably prefer that approach over using Tk::IDElayout (which is somewhat neglected).
For the Tcl::pTk approach suggested here, using the $w->ttkPanedwindow() and $w->ttkStyleConfigure() methods should eliminate the need for Tcl syntax. Since Tcl::pTk does not include complete Perl/Tk-like syntax documentation for Ttk widgets, I suggest looking through upstream Tcl/Tk documentation and Tcl::pTk::Tile POD, and then Tcl::pTk's Ttk widget demos (e.g. ttkpane.pl) to see how it comes together.
| [reply] |
|
Thank you very much for this; I've had a play with the IDEpanedwindow approach, and I agree it is quite funky - I had really hoped to be able to set expandfactors to [1, 0] and get (in effect) an inverted Panedwindow, in which the right/bottom pane would preserve its size under resizing, but the behaviour seems determinedly inconsistent when using those values.
I'll have at least a quick go at seeing if I can understand why that is before trying Tcl::pTk; I'm slightly reluctant to move wholesale to the latter unless the consensus is that it actually obsoletes Tk.
| [reply] [d/l] |
Re: Controlling resize of Tk::Panedwindow
by hv (Prior) on Mar 07, 2021 at 17:25 UTC
|
In case anyone is interested, a first cut of the application that prompted this question is now available as Turing/Life. Thank you to all those who contributed.
Hugo
| [reply] |
|
|