Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer
 
PerlMonks  

Tk::Pane widget size limit?

by jbuck (Novice)
on Aug 23, 2021 at 19:37 UTC ( [id://11136036]=perlquestion: print w/replies, xml ) Need Help??

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

Hello, I am running into a Tk issue with a large number of Tk::Label widgets within a scrolled Tk::Pane. After the widgets occupy some mysterious limit of "space", i.e. screen real estate, the widgets are no longer displayed correctly. Run the test code below and scroll all the way to the right until the last displayed Label. Swap the value of $txt to "fix" and "break" the display issue. The geometry manager used does not seem to make a difference (pack vs grid).
#!/usr/bin/perl use strict; use warnings; use Tk; use Tk::Pane; my $mw = MainWindow->new(); $mw->geometry('500x500'); my $pane = $mw->Scrolled( 'Pane', -scrollbars => 'se' )->pack( -side = +> 'left', -fill => 'both', -expand => 1 ); foreach my $col ( 1 .. 1000 ) { # try swapping the values of $txt below # my $txt = $col; # works my $txt = "Col $col"; # doesn't work # try swapping the geometry managers (same result) $pane->Label( -text => $txt, -relief => 'groove', -height => 20 )->g +rid( -row => 0, -column => $col ); # $pane->Label( -text => $txt, -relief => 'groove', -height => 20 )- +>pack( -side => 'left' ); } MainLoop;
As you see, when the width of the columns increases to accommodate the "Col" prefix to the label's text, the overall space occupied by all of the widgets increases and they stop being displayed at some point. When only the column number is displayed in the Label's text, there seems to be enough "room" and everything is rendered correctly. Is there some kind of maximum "scrolled space" beyond which Tk::Pane cannot handle? I am running perl v5.16.3 on RHEL 7.2 (don't ask)

Replies are listed 'Best First'.
Re: Tk::Pane widget size limit?
by tybalt89 (Monsignor) on Aug 24, 2021 at 00:32 UTC

    Looking at the actual X11 protocol, the 'x' and 'y' offsets within a parent window are signed shorts. It looks like that is the issue you are running into.

    Try  $txt = "Double Col $col"; and look closely at the starting labels, and also go to the right end, there are definite signs of wrapping.

      Very interesting find! That seems like quite an oversight in the X11 protocol; surely there are many programs which would need a sizeable scroll distance, regardless of how many Tk widgets are being managed. Can you think of any way to overcome this through the TK interface?

        Note also that the height and width of a window are passed in unsigned shorts, so that the max width of a window is 65535 pixels. There are not that many displays that are 65535 pixels wide...

        You could ->pack and ->packForget in a non-scrolled Pane using the scrollbar to control which of your large array of Labels are packed. Only pack a screen widths of subwidgets at a time.

        Or only create a screen widths of Label widgets, then change their contents based on the scrollbar.

        Or scroll in two dimensions.

        #!/usr/bin/perl use strict; use warnings; use Tk; use Tk::Pane; my $mw = MainWindow->new(); $mw->geometry('500x500'); my $pane = $mw->Scrolled( 'Pane', -scrollbars => 'se' )->pack( -side = +> 'left', -fill => 'both', -expand => 1 ); my $perrow = 100; foreach my $col ( 1 .. 1000 ) { my $txt = "Col $col"; # doesn't work $pane->Label( -text => $txt, -relief => 'groove', -height => 20, )->grid( -row => int +($col - 1) / $perrow, -column => ($col - 1) % $perrow ); } MainLoop;

        And here's an example of making a fixed number of Labels and changing the data in each with a scrollbar.

        #!/usr/bin/perl use strict; use warnings; use Tk; use Tk::Pane; my $offset = 0; my $labelcount = 7; my $mw = MainWindow->new(); $mw->geometry('500x500'); my $pane = $mw->Scrolled( 'Pane', -scrollbars => 'se' )->pack( -side = +> 'left', -fill => 'both', -expand => 1 ); my @data = map "Col $_", 1 .. 1000; $pane->Scale(-orient => 'horizontal', -from => 0, -to => @data - $labelcount, -variable => \$offset, -command => \&sho +w, -showvalue => 0, )->pack(-fill => 'x', -side => 'bottom'); my @labels = map { $pane->Label( -text => $data[$_], -relief => 'groove', -height => 20, -width => 8, )->pack( -side => 'left' ); } 0 .. $labelcount - 1; MainLoop; sub show { my $i = $offset; for ( @labels ) { $_->configure( -text => $data[$i++] ); } }
Re: Tk::Pane widget size limit?
by choroba (Cardinal) on Aug 23, 2021 at 19:58 UTC
    I can confirm the behaviour. You can add
    $mw->after(100, sub { $pane->xview(moveto => 1) });
    before the MainLoop so that the pane already starts scrolled right.

    Or maybe

    my $step = .05; my $i = 1; $mw->repeat(100, sub { $pane->xview(moveto => ++$i * $step) });

    to see how the scrolling happens.

    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
      Thanks but that does not answer my question or solve the problem. Is there a limitation somewhere in here? If so, is it with Tk::Pane or Tk::Scrolled? Is there a way to fix this so all widgets are always displayed correctly no matter the size or quantity?
Re: Tk::Pane widget size limit?
by kcott (Archbishop) on Aug 24, 2021 at 11:08 UTC

    G'day jbuck,

    I'm running Perl (v5.34.0) built for cygwin-thread-multi and Tk 804.036

    Firstly, I changed the shebang line to #!/usr/bin/env perl and used your suggested options: my $txt = "Col $col"; and $pane->Label(...)->pack(...);. Other than that, I used exactly the same code that you posted.

    Labels appeared correctly up to "Col 697"; the next was truncated to "Col 69". This appears to mirror what you described. There were no errors, warnings, or other messages emitted.

    Your assumption about "$col" vs. "Col $col" is not correct; although, I may have misinterpreted what you said. There is no actual resizing to accomodate the "Col " prefix. When I changed 1..1000 to 1..2000 and used "$col", labels up to "1212" appeared correctly then the next was truncated to "121" (given that the padding and borders haven't changed, this almost doubling of displayed labels is in keeping with what I roughly expected).

    While this won't change the display issue you've encountered, following the Tk::Pane documentation:

    $pane = $mw->Scrolled("Pane", ...); # add widget(s) to $pane here $pane->pack;

    will make the GUI render a lot more quickly. I didn't time it but it was noticeably faster (perhaps x5 or x10).

    If your question was purely of an academic nature — i.e. you found something and just asked about it — I would just note the limitation and move on. You could raise a bug report that either requests a fix or an addition to the doco which describes the limitation.

    If you genuinely have a requirement for a GUI that needs to render 1,000 columns, you should pick another widget. Without knowing what that application might be, I can really only suggest looking for widgets with "List", "Table" or similar in their names.

    Amongst other things, I work with biological data which can be huge (gigabytes) and is often in a CSV format with more than 1,000 columns. It occurred to me that you might be doing something similar. I've never had a requirement to present such data in a Tk GUI; however, if I did, Tk::TixGrid could be a useful option. Here's an example:

    #!/usr/bin/env perl use strict; use warnings; use Tk; use Tk::TixGrid; my $mw = MainWindow::->new(); $mw->geometry('500x500'); my $tgrid = $mw->Scrolled(TixGrid => -scrollbars => 'se') ->pack(-side => 'left', -fill => 'both', -expand => 1); $tgrid->configure(-formatcmd => sub { my ($type, @coords) = @_; $tgrid->format(grid => @coords, -bg => '#000000', -bd => 1); return; }); my $dat = 'a'; my @csv = map ["Col $_", ($dat++) x 999], 1 .. 1000; for my $c (0 .. $#csv) { for my $r (0 .. $#{$csv[0]}) { $tgrid->set($c, $r, -itemtype => 'text', -text => $csv[$c][$r] +); } } MainLoop;

    The data is highly contrived and is only intended as an example. It does show 1,000 columns and 1,000 rows (1,000,000 cells). I haven't used that module previously and was pleasantly surprised at how quickly it rendered. Of course, with substantially more data, there could still be some rendering limit. Anyway, it was purely guesswork with regards to your requirements and a fun diversion for myself.

    — Ken

Re: Tk::Pane widget size limit?
by Marshall (Canon) on Aug 25, 2021 at 09:28 UTC
    I am not really sure about your exact requirements. I made a quick hack to show 2,000 columns with the TableMatrix widget below. There is a vast difference in how this looks vs your code. This scrolls quite easily on my machine. And there are options about how to format the title row with various border presentations and colors.

    When I wrote the code that this was derived from more than decade ago, it had to run on a super wimpy lap top and I broke object encapsulation by writing the $tMain variable directly instead of calling the object's read/write methods for performance reasons. Very ugly, but it worked. You probably don't have to do that. If you do that, then the way that I caused a screen refresh was by setting the column widths again.

    I am not sure from your code what you want in terms of appearance that cannot be done with TableMatrix?

    use strict; use warnings; use Tk; use Tk::TableMatrix; use Data::Dump qw(pp); my $mw = MainWindow->new; $mw->configure(-title=> "Some Title"); $mw->geometry("1000x400+0+0"); my $table_frame = $mw->Frame(-height=>'10',-width=>'30', -relief=>'groove',-borderwidth=>'3' )->pack(-expand=>1, -fill=>'both',-pady=>'0'); my $tMain; my @col_heads = map{"col# $_";}0..1999; my $col =0; foreach my $heading (@col_heads) { $tMain->{"0,$col"} = "$heading"; $tMain->{"1,$col"} = "$heading"; $col++; } my $table = $table_frame->Scrolled('TableMatrix', -cols => scalar(@col_heads), -rows =>16, #fixed number of rows for this example # -width => 5, #minimum width in columns to be shown # -height => 10, #minimum number of rows to be shown - seems to limit! +! not Min! # -titlerows => 1, -variable => $tMain, # -selectmode => 'single', -state => 'disabled', # no direct editing of cells -resizeborders => 'col', -bg => 'white', # -rowheight => 2, -rowheight => 1, #make row display more compact.... -bd => [0,1,0,1], -justify => 'left', -drawmode => 'compatible', -wrap => 0, -relief => 'solid', -scrollbars=>'se', -exportselection =>0, )->pack(-expand =>1, -fill=>'both'); $table->rowHeight(0,2); #varies height of title row (0) #$table->tagRow('title',0); #$table->tagConfigure('title', -bd=>2, -relief=>'raised'); MainLoop;
    Update: 100,000 cells is easy with this. Could you make a simple example with perhaps 10 labels to demo the kind of "look" that you are trying to achieve?
    I really don't understand that this means: "I have 8,695 labels in a typical example (yes, I know) but the grid geometry manager is the only thing I can leverage which appropriately tracks their precise position/spacing in the layout which is very important to the data display.". I am completely unable to understand what this means from your posted example. I have sincere doubts about grid vs pack.

    Update2: I suppose that Tk:Table might be appropriate for you? Tk::Table is an all-perl widget/geometry manager which allows a two dimensional table of arbitary perl/Tk widgets to be displayed.. I don't think so, but that might be true.

Re: Tk::Pane widget size limit?
by jbuck (Novice) on Aug 23, 2021 at 23:34 UTC

    Looks like this is the same issue encountered here: Is there some limit to the max num of widgets in perl tk?

    I really can't convert everything to Tk::Canvas at this point, and I'm not even sure if a Canvas would support everything I'm doing in my real program. I have 8,695 labels in a typical example (yes, I know) but the grid geometry manager is the only thing I can leverage which appropriately tracks their precise position/spacing in the layout which is very important to the data display. Right now, I have simply cut everything in half and provide a button to choose to display either the first or second half and that works fine. But I'm curious why this is even necessary, as there are no warnings, cores, or any apparent issues/complaints from the system when I display everything at once; it just simply does not work.

      "8,695 labels"

      This has the smell of an XY problem. Perhaps if you provide more details of what you are actually doing, we could be more help.

Re: Tk::Pane widget size limit?
by Anonymous Monk on Aug 24, 2021 at 09:09 UTC

Log In?
Username:
Password:

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

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

    No recent polls found