Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number
 
PerlMonks  

Perl/Tk Optional Vertical Scrollbar Bugfix

by liverpole (Monsignor)
on Oct 24, 2010 at 18:47 UTC ( [id://867078]=CUFP: print w/replies, xml ) Need Help??

After being bitten again by the "Perl/Tk Optional Vertical Scrollbar bug", (which occurred for me almost exactly 4 years ago), I decided to write a general-purpose fix for it.

Update:  See lamprecht's post below for a much better solution (simpler, and works for all geometry managers).

Here's an example of the bug:

#!/usr/bin/perl -w # # Perl/Tk optional vertical scrollbar bug # # 102410 -- liverpole ## ############### ## Libraries ## ############### use strict; use warnings; use Tk; use Tk::ROText; ################## ## Main program ## ################## my $b_fix = 0; my $title = "Fix for Perl/Tk Optional Scrollbar Bug"; my $mw = new MainWindow(-title => $title); my $top = $mw->Frame->pack; my $f1 = $top->Frame->pack; my $f2 = $top->Frame->pack; my $bot = $f2->Frame->pack; my @args = qw( -bg white -wrap none -width 64 -scrollbars osoe ); my $rot = $bot->Scrolled('ROText', @args)->pack; my $c_out = sub { $rot->insert("end", $_[0] . "\n"); $rot->see("end") + }; my $c_quit = sub { exit }; my $c_fix = sub { nudge_widget($rot) }; if ($b_fix) { my @b1args = (-text => 'Fix (^F)', -bg => 'cyan', -comm => $c_fix +); my $b1 = $f1->Button(@b1args); $b1->pack(-side => 'left'); $mw->bind("<Control-f>" => sub { $b1->invoke }); } my $b2 = $f1->Button(-text => 'Quit (^Q)', -bg => 'cyan', -comm => $c +_quit); $b2->pack(-side => 'left'); $mw->bind("<Control-q>" => sub { $b2->invoke }); $mw->after(100 => sub { show_bug($rot, $c_out) }); MainLoop; ################# ## Subroutines ## ################# sub show_bug { my ($rot, $c_out) = @_; for (my $i = 0; $i < 64; $i++) { my $text = sprintf "%3d. Text Text Text Text", $i + 1; $c_out->($text); } }

You can see that although the code specifies -scrollbars osoe, there is no vertical scrollbar displayed in its trough, even though one is needed after populating the ROText widget.

You can run this program, and if you carefully resize the main window, never making it smaller than its original size, the vertical scrollbar will never appear.  It will only become visible if you resize it smaller than the original, or perform some other action which triggers a redisplay of the ROText widget (such as clicking the mouse within it, and scrolling up).

The simple fix is to grow the MainWindow by a single pixel in each direction, and call update on the MainWindow before and after the resize.  For example:
sub simple_nudge { my ($w) = @_; my $mw = $w->toplevel; my $geo = $mw->geometry; ($geo =~ /^(\d+)x(\d+)[+](\d+)[+](\d+)$/) or return; my ($w0, $h0, $x, $y) = ($1, $2, $3, $4); # Grow the main window by 1 pixel, then restore its original size my ($w1, $h1) = ($w0 + 1, $h0 + 1); $mw->geometry("${w1}x${h1}+${x}+${y}"); $mw->update; $mw->geometry("${w0}x${h0}+${x}+${y}"); $mw->update; }
However, this won't even work if the geometry of the ROText widget (or one or more of its parent widgets) is such that a refresh is unnecessary.

So a more robust solution is to start at the ROText widget, repacking each parent widget up to the MainWindow with -expand => 1 and -fill => 'both', calling simple_nudge on the ROText widget, and finally repacking each parent widget with its original (-expand, -fill) values.  Here's the additional code for achieving this:

sub nudge_widget { my ($w) = @_; my $mw = $w->toplevel; my $geo = $mw->geometry; ($geo =~ /^(\d+)x(\d+)[+](\d+)[+](\d+)$/) or return; my ($w0, $h0, $x, $y) = ($1, $2, $3, $4); my $a_save = [ ]; # Get current -expand and -fill values for a given widget my $c_info = sub { my $a_pack = shift; my ($exp, $fill); for (my $i = 0; $i < @$a_pack; $i += 2) { my ($key, $val) = ($a_pack->[$i], $a_pack->[$i+1]); ($key eq '-expand') and $exp = $val; ($key eq '-fill') and $fill = $val; } return [ $exp, $fill ]; }; # Save each widget's -expand and fill values for (my $this = $w; $this ne $mw; $this = $this->parent) { my $a_pack = $this->packInfo; push @$a_save, $c_info->($a_pack); $this->pack(-expand => 1, -fill => 'both'); } # Grow the main window by 1 pixel, then restore the original size simple_nudge($w); # Restore the original -expand and fill values for each widget for (my $this = $w; $this ne $mw; $this = $this->parent) { my $a_pack = shift @$a_save; my ($exp, $fill) = @$a_pack; $this->pack(-expand => $exp, -fill => $fill); } }

To see the fix in operation, set the value of $b_fix to '1' in the original program, and add the subroutines nudge_widget and simple_widget.  Now when you click on the button 'Fix (^F)', or type the ^F key, the vertical scrollbar will appear as it should have in the first place.


s''(q.S:$/9=(T1';s;(..)(..);$..=substr+crypt($1,$2),2,3;eg;print$..$/

Replies are listed 'Best First'.
Re: Perl/Tk Optional Vertical Scrollbar Bugfix
by lamprecht (Friar) on Oct 25, 2010 at 11:57 UTC
    Hi,

    the bug you describe seems to appear on windows only. It can be boiled down to the following example.
    Also this workaround is a bit more 'general-purpose' as it does not require the widget to be managed by the 'pack' geometry manager:

    use strict; use warnings; use Tk; use Tk::Text; my $mw = tkinit; my $t = $mw->Scrolled('Text', -scrollbars => 'osoe', )->pack; $t->update; $t->insert("insert", sprintf "%3d. Text Text Text\n",$_) for(0..64); $t->update; # force scrollbar refresh: # my $sb = $t->Subwidget('yscrollbar'); # $sb->set( $sb->get ); MainLoop;
    Cheers, Christoph
          seems to appear on windows only

      Yes, I did mention that in the original post.  

      And I should have said that my solution (fairly obviously) only works for the pack geometry manager.

      But your fix is much better; it's elegant *and* simple ... way ++cool.


      s''(q.S:$/9=(T1';s;(..)(..);$..=substr+crypt($1,$2),2,3;eg;print$..$/

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others wandering the Monastery: (2)
As of 2024-04-19 01:09 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found