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

I have a program in which I am trying to create a scrollbar that can scroll multiple frames. Each frame has its own scrollbar using Tk::Pane. I have found code online which provides a solution if I was using Listboxes but not for Frames. Below is my code:

#!/usr/bin/perl # Multiple Widgets with one scrollbar.pl use Tk; require Tk::Pane; $mw = MainWindow->new(); $mw->title("One Scrollbar/Three Listboxes"); $mw->Button(-text => "Exit", -command => sub { exit })->pack(-side => 'bottom'); $scroll =$mw->Scrollbar(); # Anonymous array of the three Listboxes $listboxes = [ $mw->Scrolled(Pane, -scrollbars => 'ose', -sticky => 'nsew', -background => 'green') +, $mw->Scrolled(Pane, -scrollbars => 'ose', -sticky => 'nsew', -background => 'blue'), $mw->Scrolled(Pane, -scrollbars => 'ose', -sticky => 'nsew', -background => 'cyan') +]; # This method is called when on Listbox is scrolled with the keyboard # It makes the Scrollbar reflect the chang, and scrolls the other list +s sub scroll_listboxes { my ($sb, $scrolled, $lbs, @args) = @_; $sb->set(@args); # tell the Scrollbar what to display my ($top, $bottom) = $scrolled->yview(); foreach $list (@$lbs) { $list->yviewMoveto($top); # adjust each lb } } # Configure each Listbox to call &scroll_listboxes foreach $list (@$listboxes) { $list->configure(-yscrollcommand => [ \&scroll_listboxes, $scroll, $list, $listboxes ] ); } # Configure the Scrollbar to scroll each Listbox $scroll->configure(-command =>sub { foreach $list (@$listboxes) { $list->yview(@_); }}); # Pack the Scrollbar and Listboxes $index = 0; $scroll->pack(-side => 'left', -fill => 'y'); foreach $list (@$listboxes) { $list->pack(-side => 'left'); $list->Label(-text => "One")->pack(); $list->Label(-text => "Two")->pack(); $list->Label(-text => "Three")->pack(); $list->Label(-text => "Four")->pack(); $list->Label(-text => "Five")->pack(); $list->Label(-text => "Six")->pack(); $list->Label(-text => "Seven")->pack(); $list->Label(-text => "Eight")->pack(); $list->Button(-text => "$index", -command => sub { exit})->pac +k(); $index++; } MainLoop;

When I run it, it displays my three Frames with their own individual scrollbars. But when I try to control the main scrollbar, it gives me this error:
Tk::Error: Can't call method "rooty" without a package or object reference at /usr/lib/perl5/site_perl/5.8.8/i386-linux-thread-multi/Tk +/ Pane.pm line 256. Tk::Pane::yview at /usr/lib/perl5/site_perl/5.8.8/i386-linux-thread- multi/Tk/Pane.pm line 256 Tk::Derived::Delegate at /usr/lib/perl5/site_perl/5.8.8/i386-linux- thread-multi/Tk/Derived.pm line 469 Tk::Widget::__ANON__ at /usr/lib/perl5/site_perl/5.8.8/i386-linux- thread-multi/Tk/Widget.pm line 322 main::__ANON__ at ./multiScroll2.pl line 49 Tk::Scrollbar::ScrlByPages at ../blib/lib/Tk/Scrollbar.pm (autosplit into ../blib/lib/auto/Tk/Scrollbar/ScrlByPages.al) line 372 Tk::Scrollbar::Select at ../blib/lib/Tk/Scrollbar.pm (autosplit into ../blib/lib/auto/Tk/Scrollbar/Select.al) line 201 Tk::Scrollbar::ButtonDown at ../blib/lib/Tk/Scrollbar.pm (autosplit into ../blib/lib/auto/Tk/Scrollbar/ButtonDown.al) line 159 <Button-1> (command bound to event)
This is my first post so be easy on me. Thanks!

Replies are listed 'Best First'.
Re: How to Scroll multiple Frames using Tk::Pane
by zentara (Cardinal) on Sep 09, 2008 at 19:48 UTC
    For your first post, you chose a whopper of a question....how to link nested scrolled widgets.

    First use warnings and use strict.

    Second this is kind of complex to answer, because Scrolled widgets do some internal magical linking, so trying to orchestrate them all together, and still allow them to work independently, is intricate.(More than I care to sweat over this afternoon :-)) You may be better off building ALL your widgets with manual scrollbars, then somehow juggling everything.

    But here is a start with a ScrolledPane. The only glitch is that the master scrollbar only works when you hit the up or down arrow graphics (which move things 1 unit in that direction). If you try to drag the green bar, everything resets to the master yview.

    If it was me, I would ditch the master scrollbar,and make custom labels with up/down arrows to replace the master scrollbar, and just have them do a + or - 1 unit increment, instead of the yview(@_). In other words, use a Pane, instead of the ScrolledPane, and pack a frame on the left, with an up and down label. Link each label's mouse 1 click to scroll 1 unit in all Scrolled Listboxes.

    But if you are persistent and clever, you may be able to setup a yscrollcommand that dosn't reset all listboxes to the @_ of the yscrollbar, but it's up to you, or someone else may know the trick.

    #!/usr/bin/perl use warnings; use strict; use Tk; use Tk::Pane; my $mw = MainWindow->new(); $mw->geometry("600x300+100+100"); $mw->Button( -text => "Exit", -command => sub { exit } )->pack( -side => 'bottom', -fill => 'x' ); my $parent = $mw->Scrolled('Pane' ) ->pack( -fill => 'both', -expand => 1 ); my $yscroll = $parent->Subwidget('yscrollbar'); my @listboxes; foreach my $num (1..4) { my $list = $parent->Scrolled('Listbox'); foreach my $num (1..100){ $list->insert( 'end', $num); } $list->pack( -side => 'left', -fill => 'y', -expand => 1 ); push @listboxes, $list; } $yscroll->configure( -background => "lightgreen", -troughcolor => "black", -command => sub { foreach my $list (@listboxes) { $list->yview(@_); # $list->yviewScroll(1,'units'); } }, ); MainLoop;

    I'm not really a human, but I play one on earth Remember How Lucky You Are
      Ok, thanks for the help guys! I now understand how to have the scrollbar scroll multiple frames at the same time. But, now I would like to know how to get the scrollbar to talk with the frames to have the scrollbar actually represent where it is in the frames. Also, I'd like for it to not reset the starting position at the beginning every time you click on the slider. I'm not sure if this is possible with regards to what zentara said.
Re: How to Scroll multiple Frames using Tk::Pane
by shmem (Chancellor) on Sep 10, 2008 at 14:24 UTC
    Tk::Error: Can't call method "rooty" without a package or object

    Yes, because there is no Frame subwidget to the Pane. The following does the trick:

    # Configure the Scrollbar to scroll each Listbox $scroll->configure( -command => sub { my $delta = shift; foreach my $list (@$listboxes) { $list->yview('scroll', $delta, 'units'); } } );

    See the yview method in Tk::Pane.

Re: How to Scroll multiple Frames using Tk::Pane
by zentara (Cardinal) on Sep 10, 2008 at 20:55 UTC
    Pursuing my original method, the following almost fixes it, but there is a slight lag when you change direction on the bar drag. If you release the button before changing direction, it's ok.
    $yscroll->configure( -background => "lightgreen", -troughcolor => "black", -command => sub { print "@_\n"; my( $type,$delta,$units )= @_; if($type eq 'scroll'){ foreach my $list (@listboxes) { $list->yview(@_); } } if($type eq 'moveto'){ my $num = 1; if( $delta < 0){$num = -1} foreach my $list (@listboxes) { $list->yview('scroll',$num,'units'); } } }, );

    I'm not really a human, but I play one on earth Remember How Lucky You Are