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

Am a decent way into programming my first Perl/Tk application. Since the beginning one thing has plagued me ... when I resize the MainWindow all child widgets are centred in the parent. I want them all anchored north. I've returned to this problem many times and still no solution. I've got to be missing something obvious.

Below is the code. The MainWindow contains several frames configured using "grid". A large portion of the code I've snipped out because its not relevant and too long. I also have purposely snipped out Grid row 1 for this example, that's not an error. Run this and see how you go. Thanks for your help.

Dean
#!perl use strict; use warnings; ## Import Perl modules use Tk; use Tk::Widget; use Tk::Date; use Tk::Menubutton; ## Display all shift types and create Radiobuttons for each my $shiftsframe; my $hlistbox; ########################### ## Global variables my ($endtime, $starttime); # start and end times of chosen shift ########################### ## Make Main Window my $mw = MainWindow->new (-title => 'opzTul'); $mw->resizable('false','true'); ########################### ## Make Main menu my $mainMenu = $mw -> Menu ( -type => 'menubar', -tearoff => 0); $mw->configure (-menu => $mainMenu); ########################### ## Make Admin Menu my $adminMenu = $mainMenu -> cascade ( -label => '~Admin', -tearoff => 0); my $reportsMenu = $mainMenu -> cascade (-label => '~Reports', -tearoff => 0); my $helpmenu = $mainMenu -> cascade ( -label => '~Help', -tearoff => 0); my $topframe = $mw -> Frame(-border => 1, -relief => 'sunken'); my $displaydate; my $date = $topframe->Date( -allarrows => 1, -choices => ['yesterday','today','tomorrow'], -value => 'now', -variable => \$displaydate, -fields => 'date', -selectlabel => 'Select', #-varfmt => 'datehash', ); my $shiftselect; my $All = $topframe->Radiobutton(-text => 'All day', -variable => \$shiftselect, -value => 'All' ); ########################### ## Make seperare frame for go button my $goframe = $mw->Frame; my $go = $goframe -> Button(-text => 'Go!', -width => 27, -command => [\&godate, \$displaydate, \$shiftselect] ); ########################### ## Make Middle Frames my $freshframe = $mw->Frame (-border => 1, -relief => 'sunken'); my $freshButton = $freshframe->Button (-text => 'Refresh', -width => 27, -command => [sub {$shiftsframe->DESTROY; &displayshifts; $hlistbox->DESTROY if (Exists($hlistbox)); &showhourlies; }] ); my $h1frame = $mw->Frame (-border => 1, -relief => 'sunken'); my $h2frame = $mw->Frame (-border => 1, -relief => 'sunken'); my $h3frame = $mw->Frame (-border => 1, -relief => 'sunken'); my $quitframe = $mw->Frame (-border => 1, -relief => 'sunken'); my $quitButton = $quitframe->Button ( -text => 'Quit', -width => 27, -command => \&quit); ########################### ## Make bindings to keys $mw -> bind ('<Control-q>', \&quit); ########################### ## Pack and build all elements of the window $topframe -> grid (-row => 2, -columnspan => 4, -sticky => 'n', -pady => 5, -padx => 5,); $date->pack; $All->pack; $goframe->grid (-row => 3, -columnspan => 4, -sticky => 'n', -pady => 5, -padx => 5, ); $All->select; $go->pack; $freshframe -> grid (-row => 4, -columnspan => 4, -sticky => 'n', -padx => 2, -pady => 2); $h1frame -> grid (-row => 5, -column => 3, -sticky => 'n', -padx => 2, -pady => 2); $h2frame -> grid (-row => 5, -column => 3, -sticky => 'n', -padx => 2, -pady => 2); $h3frame -> grid (-row => 5, -column => 3, -sticky => 'n', -padx => 2, -pady => 2); $quitframe -> grid (-row => 6, -columnspan => 4, -sticky => 'n', -padx => 2, -pady => 2); $freshButton->pack; $quitButton->pack; MainLoop; sub quit { print "Quitting ..\n"; $mw -> destroy; }

Edited by Chady -- added readmore tags.

Replies are listed 'Best First'.
Re: Perl/Tk - MainWindow positioning all widgets as centred
by graff (Chancellor) on Jan 19, 2004 at 03:20 UTC
    I think you could have snipped quite a bit more code in order to focus attention on the problem. Still, consider the alternative below, which keeps all the buttons etc at the top when the window is made larger.

    I'm sorry that I'm a bit at a loss to explain the subtleties involved here, except that you probably made the wrong assumption about how to organize the frames and buttons. Basically, you were using the grid manager on the main window (together with a menu bar, which might have been confusing for the grid manager), and you had separate frames within the main window for each button -- which had no impact on solving your problem.

    In the version below (with a bit more stuff clipped out) there is one frame to contain all the buttons, and the buttons themselves use the grid manager to control their positions and extents within that one frame. (As a rule, using fewer widgets is a good thing.)

    use strict; use warnings; use Tk; my $shiftselect; ########################### ## Make Main Window my $mw = MainWindow->new (-title => 'opzTul'); $mw->resizable('false','true'); # (menu bar left out for brevity) my $grid = $mw->Frame()->pack; my $All = $grid->Radiobutton(-text => 'All day', -variable => \$shiftselect, -value => 'All' ); my $goButton = $grid->Button(-text => 'Go!', -width => 27, -command => sub {print "Go\n"} ); my $refButton = $grid->Button (-text => 'Refresh', -width => 27, -command => sub {print "Refresh\n"} ); my $quitButton = $grid->Button (-text => 'Quit', -width => 27, -command => \&quit ); ########################### ## Pack and build all elements of the window $All -> grid (-row => 2, -columnspan => 4, -sticky => 'n', -pady => 5, -padx => 5,); $goButton->grid (-row => 3, -columnspan => 4, -sticky => 'n', -pady => 5, -padx => 5, ); $refButton -> grid (-row => 4, -columnspan => 4, -sticky => 'n', -padx => 2, -pady => 2); $quitButton -> grid (-row => 6, -columnspan => 4, -sticky => 'n', -padx => 2, -pady => 2); MainLoop; sub quit { print "Quitting ..\n"; $mw -> destroy; }
    update: it turns out that the "-sticky => 'n'" option in those grid() geometry manager calls is unnecessary -- this code works the same whether those lines are in or out. Sorry, but I can't seem to recall right now how to get other behaviors, such as expanding to fill available space, etc.
Re: Perl/Tk - MainWindow positioning all widgets as centred
by Popcorn Dave (Abbot) on Jan 19, 2004 at 07:29 UTC
    Have you thought of using the place geometry manager instead of the compass points?

    For the couple Perl/Tk that I've developed, I found it useful to use a graphics program suck as Paint Shop Pro or Photoshop to lay out my widgets and then use the ruler features to get my X-Y coordinates and use the place method. I found it easier to actually place my widgets exactly where I wanted them, rather than rely on the compass point method.

    Of course it's going to depend on how many and what type of widgets you are using.

    Hope that helps!

    Update: s/place command/place geometry manager/ - thanks to anonymous monk.

    There is no emoticon for what I'm feeling now.

      s/place command/place geometry manager/
Re: Perl/Tk - MainWindow positioning all widgets as centred
by JamesNC (Chaplain) on Jan 19, 2004 at 06:29 UTC
    You can get the behavior you want by creating frames and using pack on them and then using grid on the widgets inside of the frames. You have too much code for me to fix this on in your example, so, here is an example that should give you an idea of one way to accomplish what you want.
    use Tk; use Tk::Frame; use Tk::Button; my $mw = tkinit(-title, 'PM'); $mw->geometry('100x100+0+0'); my $frame = $mw->Frame()->pack(-anchor, 'nw'); my $frame2 = $mw->Frame()->pack(); #Grid bounded by frame my $btn1 = $frame->Button( -text, 'B1')->grid( -row, 0, -column, 0); my $btn2 = $frame->Button( -text,'B2')->grid( -row, 0, -column, 3); #Grid bounded by main window my $btn3 = $frame2->Button( -text, 'B3')->grid( -row, 0, -column, 1); my $btn3_1 = $frame2->Button( -text, 'B3_1')->grid( -row, 0, -column, +4); my $btn4 = $frame2->Button( -text, 'B4')->grid( -row, 1, -column, 2); my $btn5 = $frame2->Button( -text,'B5')->grid( -row, 2, -column, 3); MainLoop;

    Good luck.
    JamesNC
Re: Perl/Tk - MainWindow positioning all widgets as centred
by flyingmoose (Priest) on Jan 19, 2004 at 16:02 UTC
    Perl/Tk inspires many questions, many of them hard. This is a very basic one that you could find out on your own if you had access to a good reference or web page. This is something you learn very early with playing with pack, and i s mentioned in most every reference.

    I hate to constantly Hawk "Mastering Perl Tk" by O'Reilly, but this is an excellent guide that will serve you well if you can pick it up. It gets my five out of five stars, and is really a great in-depth guide.

    There should also be a wealth of web-based info out there, but I really can't comment on quality. I like my dead tree books. I would recommend we at PerlMonks but a Perl/Tk resources node on the Categorized Q&A page if there isn't such a node already. Sort of a "Read That Fine Manual", if you will.