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

Yesterday I submitted this question about a bug in Win32 Perl/Tk, specifically with regard to "non-appearing" sliders in a Scrollbar widget.

Today, laboring under the illusion that this might have been fixed in the latest version of Active State Perl, I downloaded the latest version from ActiveState; version 5.8.8, binary build 819 [267479], built on August 29th, 2006.  Alas, the problem remains.

However, there's unfortunately a far more serious problem now occurring (hence the submission of this as a separate post).  When text is scrolled, the size of the scrollbar changes erratically.  Sometimes in lieu of moving, the scrollbar just grows to fill the remaining distance in the trough!

So I then tried uninstalling Active State Perl, and reinstalled the older version (v5.8.7, binary build 815 [211909], built on November 2, 2005), and the problem persists.

Does anybody else see this behavior as well?  And if so, what version of Active State Perl, and what version of Perl/Tk?

Here is the code I'm using.  I find that the address "http://wikipedia.com" shows particularly egregious results when moving the slider up and down:

#!/usr/bin/perl # # Demonstrate *very* bizarre scrollbar behavior # in Win32 Perl/Tk, version 804.027-r6. # # 061029 -- liverpole # # Strict use strict; use warnings; # User-defined my $font = "arial 10"; # Libraries use Data::Dumper; use HTML::TreeBuilder; use LWP::UserAgent; use Tk; use Tk::Canvas; use Tk::ROText; # Globals my $http_url = ""; # ============================================================= # Main Program -- create the GUI # ============================================================= # my $mw = new MainWindow(-title => "Tk Version = '$Tk::VERSION'"); my $f1 = framex($mw, "^x"); my $f2 = framex($mw, "^*{443}"); my $b0 = button($f1, ">Exit (Esc)", sub { $mw->destroy }); my $pout = rotext($f2, "^*{434}"); my $e1 = labent($f1, "<HTTP Address[,64]", \$http_url); my $b1 = button($f1, "<Load (Return)", sub { load_url($http_url, $po +ut) }); $e1->focus(); MainLoop; # ============================================================ # Subroutines # ============================================================ sub load_url { my ($url, $pout) = @_; $pout->(); ($url || 0) or return; if ($url =~ s/^http://i) { $url =~ s,^//,,; } $url = "http://$url"; my $ua = new LWP::UserAgent(agent => 'Mozilla/5.0'); my $resp = $ua->get($url); if (!$resp->is_success) { $pout->("Unable to load address '$url'", "$font bold", "red"); return; } my $content = $resp->content; my $tree = HTML::TreeBuilder->new_from_content($content); my $text = $tree->as_HTML(); $pout->($text, $font); } sub button { my ($w, $opts, $ps) = @_; $opts =~ s/^([<>])//; my $side = ($1 eq '>')? 'right': 'left'; my @opts = (-bg => 'green'); push @opts, -text, $opts; ($ps || 0) and push @opts, -command => $ps; my $b = $w->Button(@opts); ($opts =~ s/\((.+)\)$//) and bind_button($b, $1); $b->pack(-side => $side); return $b; } sub rotext { my ($w, $opts) = @_; my $pfopts = get_exp_fill(\$opts); my @opts = (-bg => get_colors($w, \$opts)); push @opts, -wrap => 'word'; my $t = $w->Scrolled('ROText', @opts); $t->configure(-scrollbars => "osoe"); $t->pack(@$pfopts); my $tag = 0; my $psub = sub { my ($text, $font, $color) = @_; ($text || 0) or $t->delete("1.0", "end"); ($text || 0) and $t->insert("end", "$text\n", ++$tag); ($font || 0) and $t->tagConfigure($tag, -font => $font) +; ($color || 0) and $t->tagConfigure($tag, -background => $color +); # Workaround for "non-appearing slider" bug # See Perlmonks node 581114 $t->see("1.0"); $t->toplevel->update(); $t->see("end"); $t->toplevel->update(); }; return $psub; } sub framex { my ($w, $opts) = @_; $opts ||= ""; my $pfopts = get_exp_fill(\$opts); my @opts = (-bg => get_colors($w, \$opts)); if ($opts =~ s/\[(\d*),?(\d*)\]//) { my ($width, $height) = ($1, $2); ($width || 0) and push @opts, -width => $width; ($height || 0) and push @opts, -height => $height; } my $f = $w->Frame(@opts); $f->pack(@$pfopts); return $f; } sub labent { my ($w, $opts, $tv) = @_; $opts ||= ""; $opts =~ s/^([<>])//i; my $fr = framex($w, "$1n{004}"); my @lopts = (-bg => get_colors($w, \$opts)); my @eopts = (-textvar => $tv); if ($opts =~ s/\[(\d*),?(\d*)\]//) { my ($lwidth, $ewidth) = ($1, $2); ($lwidth || 0) and push @lopts, -width => $lwidth; ($ewidth || 0) and push @eopts, -width => $ewidth; } push @lopts, -text => $opts; my $lab = $fr->Label(@lopts); my $ent = $fr->Entry(@eopts); $lab->pack(-side => 'left', -expand => 1, -fill => 'y'); $ent->pack(-side => 'left', -expand => 1, -fill => 'y'); } sub get_colors { my ($w, $pstr) = @_; my %col = qw( b blue r red g green y yellow c cyan m magenta ); my %int = qw( 0 00 1 3f 2 7f 3 bf 4 ff ); ($$pstr =~ s/\{([^}]+)}//) or return $w->cget(-bg); my $bg = $1; exists($col{$bg}) and $bg = $col{$bg}; $bg =~ s/^([0-4])([0-4])([0-4])$/'#'.$int{$1}.$int{$2}.$int{$3}/e; return $bg; } sub bind_button { my ($b, $str) = @_; my $mw = $b->toplevel(); my $key = ""; ($str =~ s/^\^(.+)//) and $key = "Control-Key-" . lc($1); ($str =~ s/^(f\d+)//i) and $key = "Key-" . uc($1); ($str =~ s/^a-([bci])$//i) and $key = "Alt-Key-" . lc($1); ($str =~ s/^esc//i) and $key .= "Escape"; ($str =~ s/^return//i) and $key .= "Return"; ($str =~ s/^ret//i) and $key .= "Return"; ($str =~ s/^<cr>//i) and $key .= "Return"; ($str =~ s/^\[cr\]//i) and $key .= "Return"; ($str =~ /([a-z])$/i) and $key .= lc($1); $key or return 0; return $mw->bind("<$key>" => sub { $b->invoke() }); } sub get_exp_fill { my ($popts) = @_; my %sides = qw( < left > right ^ top v bottom ); my %fills = qw( x x y y n none b both * both ); my ($side, $exp, $fill); if ($$popts =~ s/^([<>^v])([xynb*])//i) { $side = $sides{$1}; my $exfi = $2; ($exp, $fill) = (($exfi =~ /[XYNB*]/)? 1: 0, $fills{lc $exfi}) +; } my @opts = ( ); ($side || 0) and push @opts, -side => $side; ($exp || 0) and push @opts, -expand => $exp; ($fill || 0) and push @opts, -fill => $fill; return [ @opts ]; }

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

Replies are listed 'Best First'.
Re: Very strange Scrollbar behavior in Win32 Perl/Tk version 804.027
by graff (Chancellor) on Oct 29, 2006 at 16:26 UTC
    Having tried this out, I could offer an alternative point of view: the problem is not so much with the Tk scrollbar behavior, but is rather due to an interaction between how the scrollbars work and the kind of text data you are loading into the scrolled widget.

    If you add this line to the "load_url" sub, the widget behavior will be more "normal":

    $text =~ s/>/>\n/g; # add this right after "my $text = $tree->as_ +HTML()"
    The point is that the scrollbar slider's size is based on line count and the number of lines visible in the scrolled widget at a given moment, as well as the total percentage of text visible (or something to that effect).

    If the number of text lines (i.e. the number of substrings conjoined by explicit line-feed characters) is less than the height of the Tk::Text window, but the lines are really long and get wrapped beyond the height of the window, you have a situation where the slider-sizing logic (and possibly other aspects of scrollbar behavior) will likely run into boundary conditions, or situations where "reasonable defaults" are at best much more difficult to establish and implement.

    I think the exact behavior of OP code may depend on whether the html data contains any line-feeds as text content, but I'm not sure about that, just as I'm not sure yet what HTML::TreeBuilder's "as_HTML()" method does to web-page data in terms of preserving or removing line-feed characters. (Maybe that'll be explained in the docs; I just haven't looked yet.)

    So, if you simply take one or two simple measures to provide a sensible concession to human readability, things will go better, because the widgets seem to have been designed with some built-in assumptions about that sort of thing.

      Excellent answer, and ++graff.

      Thank you very much for clearing up that mystery.  I was getting quite worried when *both* of my Perl installations were acting so bizarre.

      Apparently this is only an artifact of having huge amounts of text in a Text widget, -without- any newlines.  After applying your simple one-liner $text =~ s/>/>\n/g;, the Text widget is behaving as it should.


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

        If you change line 86 of your code, to turn off wrapping:push @opts, -wrap => 'none';, you also get more normal scrollbar behaviour.


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Very strange Scrollbar behavior in Win32 Perl/Tk version 804.027
by vkon (Curate) on Oct 29, 2006 at 22:38 UTC
    actually my wrong yesterday reply is not wrong here.

    The scrollbar button size problem *is* well known and fixed in Tk version 8.5.

    BTW why you keep pointing you're on Win32? Perl is so crossplatform!
    I mean - if you figure out cross-platform differences between perl behaviour (behaves here but misbehaves elsewhere) - then yes, start pointing the $^O.

    BTW I sometimes use WinCE but often am silent about that
    :) :) :)

      Platform information is often useful up front because Perl is cross-platform and people who only use a single platform are often unaware that a problem may be isolated to their context. At the very least others can then report reproducing the problem (or not) and possibly start narrow the scope of the problem.

      Many things are not platform sensitive. However GUI and file system related things very often are. A brief heads up in those cases saves time for the OP and for whomever may be replying.

      Version information is always useful up front where buggy behaviour is being reported.


      DWIM is Perl's answer to Gödel
      The platform does, in fact, make a difference.

      To briefly cite some specific examples:

      1> Perl/Tk's fileevent handler doesn't work in Windows.
      2> caller() doesn't return the proper line number on all Windows machines.
      3> print SCK $stuff doesn't work on the E-Machines T2862 but seems to work just fine on other models of E-Machines ( a severely aggravating problem ).

      Ideally, cross-platforming works perfectly. Unfortunately, the world ain't ideal.

      Peace, monks.

      Bro. Doug :wq
        all true, but platform difference should be minimal, and somewhat platform-specific.

        When speaking on non-platform specific GUI element, it should behave everywhere consistently, that is why first attention should be paid to logic and widget, and only afterwards we should consider whether misbehaviour is $^O-specific!

        BTW I've never thought of Perl/Tk's fileevent as non-working on Windows
        Did you encountered difficulties with it?