Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much
 
PerlMonks  

Controlling resize of Tk::Panedwindow

by hv (Parson)
on Mar 01, 2021 at 18:47 UTC ( #11128956=perlquestion: print w/replies, xml ) Need Help??

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();

Replies are listed 'Best First'.
Re: Resizing paned Tk::Canvas
by choroba (Archbishop) 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]

      Ah thanks, I managed to miss that despite a couple of readings.

Re: Resizing paned Tk::Canvas
by LanX (Sage) 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! :)

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery

Re: Controlling resize of Tk::Panedwindow
by tybalt89 (Prior) on Mar 03, 2021 at 01:36 UTC

    Does this do what you want?

    #!/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;

      Ah! It certainly appears to do what I want, and appears to be robust with everything I've thrown at it so far. I shall see what happens when I shoe-horn that into my nascent application.

      Thank you very much. :)

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.

      > While incorporating Tcl/Tk 8.5+ or Ttk into Perl/Tk continues to seem unlikely

      FWIW, I think he could also migrate to Tkx (which has another interface) to use newer versions of Tcl/Tk.

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      Wikisyntax for the Monastery

        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.

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.

    Cheers - L~R

      Thanks Limbic~Region; I had surmised as much from searching through possibly related nodes, but it seems zentara's appearances here are increasingly rare (somewhat like my own).

        he passes by from time to time, not always bothering to log in when posting.

        You might need to come again in some weeks... :)

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        Wikisyntax for the Monastery

Re: Controlling resize of Tk::Panedwindow
by kcott (Bishop) on Mar 02, 2021 at 07:47 UTC

    G'day Hugo,

    I would've implemented the layout you describe as follows.

    #!/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.

    — Ken

      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).

      Missing adjusters
Re: Controlling resize of Tk::Panedwindow (IDELayout IDEpanedwindow)
by Anonymous Monk on Mar 02, 2021 at 02:49 UTC

    Hi

    Try Tk::IDElayout it provides a https://metacpan.org/pod/Tk::IDEpanedwindow#expandfactors

    Its not exactly perfect but try it out

    #!/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

      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.

      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.

Re: Controlling resize of Tk::Panedwindow
by hv (Parson) 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

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11128956]
Approved by LanX
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others chilling in the Monastery: (4)
As of 2021-09-19 14:57 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?