Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation
 
PerlMonks  

Re^2: TK Placing Widgets in a Scrolling Pane

by saiftynet (Initiate)
on Dec 03, 2021 at 19:56 UTC ( [id://11139373]=note: print w/replies, xml ) Need Help??


in reply to Re: TK Placing Widgets in a Scrolling Pane
in thread TK Placing Widgets in a Scrolling Pane

Learned Brother Ken,

Thank you so much for the insight. I code poorly, largely because I borrow code from here and there and crowbar some functionality more by chance than intelligent design. Your teachings are helpful and will probably completely alter my code for the better.

The rather bizarre looking $canvas object was from a progressive overloading of an initially simple object that accumulated more and more functionality. I am, I am ashamed to say, the author of GUIDeFATE; GUIDeFATE results in the production of a GUI, returning a single object that can be used to query/manipulate all the widgets, as well as being able to manipulate the canvas itself. You will immediately get the impression that my failings have already permeated widely in the code affecting multiple sub-modules as I struggled to get a common method for managing multiple different back-end toolkits.

My goal had been to be able to generate a scrolling pane of a predetermined size, placed in a specific location in the window. (hence the need for "place"). This was then to be populated by Tk::Checkbuttons or their equivalent in other toolkits...but if I use relative positioning to place these widgets, they leak out of the Pane widget, rather than remain contained somewhere in the scrollspace of the pane (perhaps unsurprisingly). The vast majority of the examples I have seen on the interweb use ->pack() to produce a list of checkbuttons

But I am grateful for your wisdom. I know I have to do a major rewrite but the fear is great

saif

  • Comment on Re^2: TK Placing Widgets in a Scrolling Pane

Replies are listed 'Best First'.
Re^3: TK Placing Widgets in a Scrolling Pane
by Marshall (Canon) on Dec 04, 2021 at 01:19 UTC
    Hi Saif,

    Thank you for providing runnable code! But I am still not sure exactly what you are trying to achieve?

    I think you "short-sell" pack(). This the most commonly used geometry manager. The more complex ones like grid() are less commonly used. I have never used Canvas.

    When using pack(), you need to think about packing Frames within Frames. Think of a Frame as a widget unto itself. The most common mistake when using pack() is to not use enough Frames.

    In the below code, I did have trouble getting the required minimum amount of "blank violet colored space" on the screen. But I haven't coded an Tk in a long time. The main idea with pack, is that if you want your list box to have some indentation from the left, or perhaps to center it on the screen, make a Frame which contains a "dummy" spacer frame, then your Listbox and pack appropriately (often when using enough frames, the default pack will be fine).

    When using pack() with some complicated GUI object that needs multiple widgets to "line up" in a vertical sense, get that working say in simple main window Frame on the left hand side of the screen. Then instead of using the mainWindow, put that stuff into a separate Frame and pack that Frame probably within a Frame within the mainWindow.

    #!/usr/bin/perl use strict; use Tk; my $mw = MainWindow->new; #$mw->geometry('400x250'); #some issues with this... #see my post my $FirstFrame = $mw->Frame( -bg => 'lavender', -relief => 'sunken', -width => 400, -height => 250)->pack(-expand => 1, -fill => 'both'); my $spacer_frame = $FirstFrame->Frame( -width =>10, # ADJUST THIS TO SEE WHAT IT DOES )->pack(-side => 'left'); my $listbox = $FirstFrame->Scrolled ('Listbox', -bg => 'white', -scrollbars => "e", -selectmode => 'extended', -width => 10, -height => 5, )->pack(-side=>'left'); my @strings2 = qw/apples bananas pears grapes/ x 5; $listbox->insert('end',@strings2); MainLoop();

      G'day Marshall,

      You asked me two questions about your code (via /msg). Generally, I'd recommend you actually post these questions; that way, if I'm unavailable, someone else could answer them. I'll answer the second question first: it applies to the answer to the first question.

      "With the geometry statement, I couldn't get the listbox to appear at top of the main frame"

      That has nothing to do with geometry(). If you manually resize the GUI, you'll see the Listbox in the centre of the left-hand side. Look for -side and -anchor in Tk::pack. The former defaults to top, you've changed it to left, that's where it appears, all good so far. The latter defaults to center, you haven't changed that, so it appears in the centre, not what you want; had you changed that to n, it would appear at the top (which is where you want it).

      "Maybe you can show me how to make my code work as OP intended"

      Here's a brief list of changes I made to your code:

      • Shebang: that's just for me; I don't use the system Perl — you possibly don't need this change.
      • Added use warnings; — you should have this near the top of all Perl code.
      • Reinstated $mw->geometry('400x250');.
      • Removed the -width and -height from $FirstFrame.
      • Removed the entire $spacer_frame — see -padx below. (This might be useful in a more complex GUI, but I considered it unnecessary here.)
      • Multiple changes to $listbox:
        • Widget options -width and -height now use the OP's original, scaled $size values. (Yes, hard-coded for demo purposes only; but, as I said in my original reply, "generally a bad move".)
        • Added pack() options: -anchor n -padx 50 -pady 12. See my first answer (above) for an explanation of -anchor. The -padx and -pady options use the OP's original $location values. The -padx option handles what the removed $spacer_frame was doing.

      Here's the modified code:

      #!/usr/bin/env perl use strict; use warnings; use Tk; my $mw = MainWindow->new; $mw->geometry('400x250'); my $FirstFrame = $mw->Frame( -bg => 'lavender', -relief => 'sunken', )->pack(-expand => 1, -fill => 'both'); my $listbox = $FirstFrame->Scrolled('Listbox', -bg => 'white', -scrollbars => "e", -selectmode => 'extended', -width => 200/7, -height => 212/15, )->pack(qw{-side left -anchor n -padx 50 -pady 12}); my @strings2 = qw/apples bananas pears grapes/ x 5; $listbox->insert('end',@strings2); MainLoop();

      This code now renders exactly the same as the OP's original code.

      There is only one difference in functionality that I detected. If you manually resize the GUI, with this code, the Listbox will also resize; with the OP's code, the Listbox will be chopped off on the right, at the bottom, or possibly on both of those sides. In either case, I can still scroll the list with the mousewheel. So that's a serendipitous improvement.

      — Ken

      Hi Brother Marshall

      Thank you for that, I am beginning to understand sort of how the hierachy works...so Frames can take subFrames and scrolling listboxes in them...I need a scrolling structure (Frame,Pane, Whatever) to take multiple rows of Checkbuttons which behave as a scrlled item behaves...without leaking out of the parent Frame/Pane etc. But I will try and do as you say. Thank you.

        Try this:

        #!/usr/bin/env perl use strict; use warnings; use constant { LIST_W => 28, LIST_H => 14, LIST_X => 50, LIST_Y => 12, }; use Tk; use Tk::HList; my $mw = MainWindow->new; $mw->geometry('400x250'); my $hlist_F = $mw->Frame()->pack(qw{-expand 1 -fill both}); my $hlist_scrl = $hlist_F->Scrolled(HList => -scrollbars => 'osoe', -columns => 1, -header => 0, -itemtype => 'window', -width => LIST_W, -height => LIST_H, )->pack( -fill => 'y', -side => 'left', -anchor => 'n', -padx => LIST_X, -pady => LIST_Y, -ipadx => 5, -ipady => 5, ); my $hlist = $hlist_scrl->Subwidget('scrolled'); my @colours = qw{ red green blue yellow cyan magenta orange teal purple pink lime azure rose olive lilac black grey white gold silver bronze }; my (%palette, @cboxes); for (@colours) { $palette{$_}{val} = 0; $palette{$_}{cb} = $hlist->Checkbutton( -text => $_, -variable => \$palette{$_}{val}, -anchor => 'w', -pady => 0, ); push @cboxes, $palette{$_}{cb}; } $hlist->add("$_", -widget => $_) for @cboxes; MainLoop();

        I believe it covers all the bits that you want.

        — Ken

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others having an uproarious good time at the Monastery: (3)
As of 2024-04-19 21:45 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found