Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw
 
PerlMonks  

Tk autosizing Scrolled widgets

by olgo (Acolyte)
on Sep 13, 2021 at 09:28 UTC ( [id://11136705]=perlquestion: print w/replies, xml ) Need Help??

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

Greetings! Is there a way of getting a Tk Scrolled (Subwidget) Pane to automatically resize up to a limit (typically screen limitations)? It seems the dimensions of the Tk Scrolled widget needs to be specified explicitly, either when defining the widget or later using -configure(). I would want my main window and all contained widgets to expand with my dynamically defined Scrolled widget contents, and the scrollbars appear only when there is no place left to expand. Using Strawberry 5.32 on a Win32 system.

use Tk; use Tk::HList; use Tk::Pane; use strict; my $Window = MainWindow->new(); $Window->geometry("+0+0"); $Window->maxsize(1000,1200); $Window->minsize(400,300); my $tab = $Window; my $scroll = $tab->Scrolled('Pane', -sticky => 'news', -scrollbars => 'osoe', ); $scroll->pack; my $pane = $scroll->Subwidget("scrolled"); my $grid = $pane->HList( -columns => 13, -width => 0, # Causes scrollbar to appear -height => 0 # Causes scrollbar to appear ); $grid->pack(); $scroll->pack(-expand => 1, -fill => 'both'); foreach my $row (0..10) { $grid->addchild(""); foreach my $col (0..12) { my $wid = $grid->Entry( -text => "Whatever", -width => 0, ); $wid->pack; $grid->itemCreate ($row, $col, -itemtype => 'window', -widget => $wid); } } #$pane->configure(-height => '1000', -width => '1000'); # Works, but s +hould be handled by pack MainLoop;

Replies are listed 'Best First'.
Re: Tk autosizing Scrolled widgets
by kcott (Archbishop) on Sep 13, 2021 at 11:53 UTC

    G'day olgo,

    Welcome to the Monastery (at least with respect to your first post; I see you registered about a decade ago. :-)

    We had a very similar question last week: "Seeking way to dynamically change listbox height". The solution posted there may work for you also.

    — Ken

      Ken, thank you for your prompt response. Indeed, I have been a seeker of perl wisdom for a number of decades while producing some 50k lines of perl code, but this is my first post in a while.
      The referred question leads in the direction that this may not be so easily solved using the Scrolled method. Packing and scrolling are somewhat counter direction mechanisms...
      Manually handling the scrollbars is probably what I need to do, but I can imagine there being issues with slightly different sized Panes depending on whether or not the scrollbars are needed etc. Or maybe the packer handles a not needed scrollbar for me? Time will tell.

      I wouldn't be surprised if some monk has already encapsulated this somewhere.

      My general problem is to pack as much information as possible in as little a GUI as possible, keeping as much as possible visible until I run into the limits of the screen and only then showing the scrollbars.

      Any further hints or pointers greatly appreciated.
      Again, thanks.

Re: Tk autosizing Scrolled widgets
by tybalt89 (Monsignor) on Sep 13, 2021 at 23:29 UTC

    If I understand your question (and I'm pretty sure I don't), you are trying to make a grid of widgets that has a fixed minimum size but will expand as the main window expands. I don't think you really want to put the grid in a HList because that's for hierarchical lists like directories, not grids. Here's a grid based Tk app that does what I think you want.

    #!/usr/bin/perl use strict; # https://perlmonks.org/?node_id=11136705 use warnings; use Tk; use Tk::Pane; my $mw = MainWindow->new(); $mw->geometry("+0+0"); $mw->maxsize(1000,1200); $mw->minsize(400,300); my $scroll = $mw->Scrolled('Pane', -scrollbars => 'osoe', -sticky => 'news', )->pack(-expand => 1, -fill => 'both'); my $f = $scroll->Frame->pack(-expand => 1, -fill => 'both'); foreach my $row (0..10) { foreach my $col (0..12) { $f->Entry( -text => "rc $row $col", -width => 0, )->grid(-row => $row, -column => $col, -sticky => 'news'); $row or $f->gridColumnconfigure($col, -weight => 1); } $f->gridRowconfigure($row, -weight => 1); } MainLoop;
      Perhaps I have misunderstood the OP's requirements?
      But your code should work with:
      #$mw->maxsize(1000,1200); #$mw->minsize(400,300);
      If I understood correctly, the idea is to size the window so that all data can be shown without scrollbars, if possible.

      Update: Your code is interesting. I'm not sure either one of us really understands the OP's requirement.

      Update2: Now that I look at your code vs mine... The main difference is that I use pack() instead of grid(). With weird shaped GUI regions, pack() tends to work better as long as you are using enough frames. In general with more than one object, you put them into a Frame and than pack that frame into a frame. Grid() is different and I haven't used it. But this can work well if every row is the "same" (i.e., lining up the columns).

      The main thing appears to be that the OP will need to calculate desired width size and then use that value to configure the window.

Re: Tk autosizing Scrolled widgets
by Marshall (Canon) on Sep 13, 2021 at 22:23 UTC
    I think that you have the first part, that the scrollbars disappear when they are not necessary.

    I think what you want is: When the display pops up onto the screen, it should use the entire height and width of the monitor and not have any scrollbars unless they are necessary? Since you have solved the first part of the problem (scrollbars disappear if the aren't needed). This comes down to the equivalent requirement of how to size the window so that you can see everything without scrollbars, if possible?

    There isn't any pack() parameter, to my knowledge that says "use entire screen space".
    I think you will have to calculate your "ideally" required space (height and width in pixels), and compare that with the pixel resolution of the monitor that you are running on. If there aren't enough pixels available, then the best that you can do is have a window of the max monitor's pixel width.

    These functions are available:

    $widget->reqheight #requested height $widget->height #actual height $widget->reqwidth #requested width $widget->width #actual width
    It been a very long time since I worked with Tk. I'm not familiar with some of the widgets that you used, so I wrote my own example to play with.

    What I wanted to show is how to count up pixel widths of objects and then use that total to configure the window size. For some reason the configure method didn't work in my testing, but but I'm sure that is some kind of brain cramp on my part. I just set the minimum width of the window to size needed for the columns shown. I added a 20 pixel "fudge factor" at the end of the row to account for the scroll bars in my example which work differently than yours. I just did the width calculation, but height would be similar.

    Anyway here is my hacking code for further thought..

    use Tk; use Tk::Pane; use strict; use warnings; my $Window = MainWindow->new(); $Window->geometry("+0+0"); # start in upper left corner of display my $sframe = $Window; my $scroll = $sframe->Scrolled('Pane', -sticky => 'news', -scrollbars => 'se', ); $scroll->pack(-expand => 1, -fill => 'both');; my $total_row_width = 0; foreach my $row (0..9) { my $row_frame = $scroll->Frame()->pack(-side=>'top',-fill=>'x'); $total_row_width = 0; foreach my $col (0..12) { my $this_entry =$row_frame -> Entry(-text => "Whatever $row,$co +l", -width => 12)->pack(-side = +> 'left'); my $width_this_widget = $this_entry->reqwidth; $total_row_width += $width_this_widget; } #print "width in pixels this row of widgets: $total_row_width\n"; } my $fudge = 20; print "total row width = $total_row_width\n"; $Window->minsize($total_row_width + $fudge,300); MainLoop;
    You will of course have to figure out the pixel width of the monitor that you are running upon. But that is not a Tk function to my knowledge.
    Also be aware that Tk sometimes uses "width in characters" instead of pixels. But that is only an approximate measure (see my width of Entry window).

      It seems that my original post lacked a bit of context so I will give it some more effort here:
      The code example I posted was simply an effort to reduce the problem to highlight the issue I was having, i.e. the autosizing of the variable grid data.

      My entire GUI consist of many more elements, but the rest I have already got working, at least sufficiently.

      The screen consists of a starting upper left block of widgets; Labels, Entrys, Checkboxes, BrowseEntrys and ProgressBars. Nothing strange there.
      Then comes the varying part of the GUI: A grid (based on an HList in my case) that contains all the dynamic data, in response to what the user does with the top widgets.
      My dynamic grid consists of lines of varying column content, Entries, Labels, BrowseEntrys and Checkboxes, all with varying dimensions.
      In the case where the dynamic grid contains only a limited amount of data, I want all the data to be visible, no scrollbars and the outer window tightly snug around the entire GUI.
      In the case where the dynamic grid contains massive amounts on data, I want as much data as possible to be visisble and scrollbars available to be able to scroll the dynamic grid data. The outer window should in this case extend to the entire screen (width/height wise depending on which direction the data extends)

      tybalt89: Thanks for the alternative method of producing the grid data. I considered this method before but discarded it due to having to use the grid packing method.
      There was a note somewhere saying one should avoid mixing packing methods and I have used only form so far (not pack as in my example). However, seeing your example code, I will definately have a go at it.
      Your code example however still produces scrollbars when adding more data in the grid (Even your example code produces a horizontal one).

      Marshall:You code does solve the problem.
      Enlarging the window by means of changing the window MinSize is however not what I want (I want the user to be able to resize it at will), but -configuring the scrolled pane size worked equally well.

      Conclusion
      If this is indeed the best/only solution, I will have to sum up the total of all my top widgets and dynamic grid contents.
      I still have the feeling that there should be some neat Tk packing or whatever mechanism for doing this but maybe there isn't.
      Giving this type of task to the "application" seems wrong. Best solution would be to add this as a new option to the packer algorithm. Maybe this could be added as a Tk request somewhere?

      Getting answers (and even programming efforts) to my question in less than 24h is way more than I expected.
      Thank you all.

        The mixing of ->pack and ->grid only applies within ONE parent, different parents can have different geometry managers within one application. No Problem. I do it all the time. Example follows.

        Applications resizing themselves without user input is a BAD IDEA. Just imagine your user trying to click on something and having it move out of the way just before the click. BAD IDEA!

        See the "widget" demo program for an example of what an HList looks like. It should have come with the Perl/Tk package.
        "I do not think it means what you think it means."

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (4)
As of 2024-04-19 04:14 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found