jbuck has asked for the wisdom of the Perl Monks concerning the following question:

Hello Monks,

I am having an issue re-packing an adjuster frame in between two other widgets. The left widget is a listbox, displaying database search results. The right widget is an ROtext, displaying detailed information about the list on the left. In between them is an Adjuster, which allows the user to adjust how much of each widget is "in view". This works fine.

My issue is that I have a special search case, which does not contain detailed data and thus does not require the adjuster or the ROtext. So I "packForget" those widgets and just display the listbox. When the user returns to the "normal" search type, I "re-pack" the adjuster and ROtext. However, the adjuster always seems to encroach into the ROtext frame. Or, maybe more accurately, pulls away from the listbox.

You can demonstrate this behavior by running my code, and switching between the two search types. When the GUI is first constructed, everything looks fine. Then when you switch to the "list only", and back to "list and data", the adjuster has moved! I cannot figure out where my pack error lies. I just want the adjuster to come back in the same place as it was originally! Please help, and thanks!!

#!/apps/perl/bin/perl use strict; use warnings; use Tk; use Tk::Adjuster; use Tk::ROText; my $mw = MainWindow->new(-width=>1500,-height=>650); $mw->packPropagate(0); my $topFrame = $mw->Frame(-relief => 'groove', -borderwidth => 2)-> pack(-side => 'top', -anchor => 'n', -fill => 'x'); my $searchFrame = $topFrame->Frame()-> pack(-side => 'left', -anchor => 'w', -padx => 8, -pady => 3); my $list = $mw->Scrolled("Listbox", -scrollbars => 'se', -selectmode => 'single')-> pack(-side => 'left', -padx => 3, -expand => 1, -fill => 'both', -a +nchor => 'w'); my $RO_text = $mw->Scrolled("ROText", -scrollbars => 'se', -wrap => 'word')-> pack(-side => 'left', -anchor => 'w', -fill => 'both', -expand => 1 +); my $adjuster = $mw->Adjuster()->packAfter($list, -side => 'left'); my $searchType; my @searchOptions = ( 'list_and_data', 'list_only' ); $topFrame->Optionmenu( -variable => \$searchType, -options => \@searchOptions, -command => [ \&changeSearchType, \$searchFrame +, \$list] )-> pack(-side => 'right', -anchor => 'w', -padx => 5, ipadx => 3); $topFrame->Label(-text => 'Search Type:')->pack(-side => 'right', -anc +hor => 'w'); MainLoop; sub changeSearchType { if( $searchType eq 'list_only' ) { $RO_text->packForget; $adjuster->packForget; $list->pack(-side => 'left', -expand => 1, -fill => 'both', -anc +hor => 'w'); my @results = ("apple","banana","orange"); $list->delete(0,'end'); $list->insert('end',\@results); } else { $adjuster->packAfter($list, -side => 'left'); $RO_text->pack(-side => 'left', -expand => 1, -fill => 'both', - +anchor => 'w'); my @results = ("apple","banana","orange"); $list->delete(0,'end'); $list->insert('end',\@results); $RO_text->delete('1.0','end'); $RO_text->insert('end',"These are examples of fruit"); } } 1;

Replies are listed 'Best First'.
Re: Issue packing a Tk::Adjuster
by beech (Parson) on Apr 19, 2016 at 01:58 UTC
    Well, I looked inside Tk::Adjuster,

    you can tweak position with  $adjuster->delta_width(-120); but its kinda clumsy,

    so you can also do what delta_width ultimately does which is slightly less clumsy  $adjuster->slave->GeometryRequest( 120, $adjuster->slave->height);

    update:  $adjuster->slave->GeometryRequest( $adjuster->parent->width/6 , $adjuster->slave->height);

Re: Issue packing a Tk::Adjuster
by Marshall (Canon) on Apr 18, 2016 at 23:06 UTC
    Its been years since I fiddled with Tk, but you may find this helpful, $widget->packForget() method. There is also a @list = $widget->packInfo( ); method. I am not sure if the link I found with google is a "legal" open source book, but you can some google yourself. I am thinking that since "pack" worked the first time, if you make it "forget" and start over, you will get a result the second time, like the first time.

    Update: struck this because I see the forget method now and I am lost. Sorry for the bandwidth waste. However, packInfo() may hold some promise..

    Update 2: First, most excellent demo program! I am using Active State 5.20 and all I needed to do was install Tk via the ppm (Perl Package Manager) GUI. With my version, yes, the panels get resized when switching between modes. But of course the user can easily move the adjuster back to "where it was". Of course that is a hassle! I did not see any other functional problems, just user inconvenience and annoyance.

    I tried a lot of things including getting packInfo() and trying to use that for the re-pack but that didn't pan out for me. Oops. I am wondering now in a speculative way that repacking $list in the "list only view" to expand it somehow changes it so that it can't repack in the same way like it did before with the other objects? One completely untested but perhaps an idea to test, is to "forget" all the objects:list,adjuster,ROtext. Make a new list object, $list2 and use that to pack into the now "list only" panel. To go back, forget that $list2 object and re-pack the 3 objects that haven't been mucked with? This problem is not so easy, but your demo is excellent.

    One extremely minor problem that you've probably already seen, there is one place where there is  ipadx => 3, should be -ipadx, but this is just a non-consequential error.

Re: Issue packing a Tk::Adjuster
by Anonymous Monk on Apr 19, 2016 at 01:16 UTC

    Try packing the adjuster after packing the RO_text in the else block of the sub.

Re: Issue packing a Tk::Adjuster
by Anonymous Monk on Jul 10, 2019 at 05:36 UTC
    Wow, three years later and believe it or not, this tool lives on! It's actually an incredibly complex and comprehensive tool used extensively on a massive engineering program. My tiny test program here is but a fraction of a fraction of a simplified snippet of the code!

    Anyway, I'm updating the program now and think I've figured out a solution. I wanted to post here in case it helps others.

    The $adjuster->slave->GeometryRequest indeed seems to be an answer, albeit there could still be a more elegant solution out there.

    By giving GeometryRequest the arguments of ($adjuster->parent->width * 0.2, $adjuster->slave->height) I seem to have gotten it to behave as desired, at least in the full program!

    I'm not sure why this works exactly, but assigning the adjuster 20% of the available width seems to help? I should mention there is another method that gets called immediately after, which resizes the column widths in what is actually an MListbox, to occupy the entire available space. However, I was seeing the same problematic behavior without the GeometryRequest, and it seems to work with it!