2

Using Perl Tkx, I'm attempting to create a window with a treeview widget and a scrollbar to the right of it. I need the treeview widget to automatically resize when the user resizes the window.

This is what I have:

my $mw = Tkx::widget->new(".");

my $frm = $mw->new_ttk__frame(-padding => "2 6 12 12");
$frm->g_grid(-column => 0, -row => 0, -sticky => "nwes");
$frm->g_pack(-expand => 1, -fill => 'both');

my $tree = $frm->new_ttk__treeview;
$tree->g_grid(-column => 1, -columnspan => 5, -row => 1, -sticky => "we");
$tree->g_pack(-expand => 1, -fill => 'both');

my $scrollbar = $frm->new_ttk__scrollbar(-orient => 'vertical', -command => [$tree, 'yview']);
$scrollbar->g_grid(-column => 6, -row => 1, -sticky => "we");
$scrollbar->g_pack(-expand => 1, -fill => 'both');

$tree->configure(-yscrollcommand => [$scrollbar, 'set']);

Both widgets are displayed in the window, and the resizing works, but unfortunately the scrollbar is placed underneath the tree, not to the right of it. If I remove the three g_pack(-expand => 1, -fill => 'both') lines, the positioning is correct, but the resizing doesn't work. How can I place the scrollbar to the right of the tree, and have the automatic resizing work?

Borodin
  • 126,100
  • 9
  • 70
  • 144
epsilon_j
  • 325
  • 4
  • 14
  • Are you tied to Tk? The classic solution is to put both the treeview and the scrollbar in a container frame. Would that work for you? – Borodin Oct 01 '15 at 20:05

2 Answers2

3

You're using both grid and pack to layout widgets into the same container, which is not supported. The first step would be to use only pack everywhere since you have a simple arrangement for the widgets.

Using -expand => 1 for the scrollbar means that Tk will try and give it as much space as possible. You don't want that for the scrollbar since it should only be allocated just enough space for itself. I have changed -fill to 'y' as a matter of style, but it doesn't seem to make much of a difference.

$scrollbar->g_pack(-expand => 0, -fill => 'y');

pack will arrange widgets one below the other by default. So, you should add a -side parameter if you need a horizontal arrangement starting from the left:

$tree->g_pack(-expand => 1, -fill => 'both', -side => 'left');
$scrollbar->g_pack(-expand => 0, -fill => 'y', -side => 'left');

I recommend you read through the excellent Mastering Perl/Tk book, especially the section about the pack geometry manager. This book uses the Tk module and not Tkx, but I think it should be easy to map concepts between both.

svsd
  • 1,831
  • 9
  • 14
3

It's okay to use multiple geometry managers within your application but you can't mix them when arranging the children of a particular widget. Either pack or grid would work here; you need to pick one and stick with it.

When using pack you need to specify the side of the parent container on which to pack the widget. (The default is top if unspecified). Since you want to place your tree and scrollbar side-by-side, use left. You only want the scrollbar to fill the available vertical space. You don't want it to fill horizontal space. When packing it change -fill from both to y and remove -expand (or set it to 0).

use Tkx;
my $mw = Tkx::widget->new(".");

my $frm = $mw->new_ttk__frame(-padding => "2 6 12 12");
$frm->g_pack(-expand => 1, -fill => 'both');

my $tree = $frm->new_ttk__treeview;
$tree->g_pack(-side => 'left', -expand => 1, -fill => 'both');

my $scrollbar = $frm->new_ttk__scrollbar(-orient => 'vertical', -command => [$tree, 'yview']);
$scrollbar->g_pack(-side => 'left', -fill => 'y');

$tree->configure(-yscrollcommand => [$scrollbar, 'set']);

Tkx::MainLoop();

If you choose to use grid instead, you need to set sticky to make the widgets expand to fill their cells and configure rows/columns to define how they should respond to a resize. You want the tree to stick to all sides (nsew) and the scrollbar to stick to the top and bottom (ns). The tree should be the cell that claims available space on a resize so we configure it's cell to have a weight of 1 and leave the cell with the scrollbar with a default weight of zero.

use Tkx;
my $mw = Tkx::widget->new(".");

my $frm = $mw->new_ttk__frame(-padding => "2 6 12 12");
$frm->g_pack(-expand => 1, -fill => 'both');

my $tree      = $frm->new_ttk__treeview;
my $scrollbar = $frm->new_ttk__scrollbar(-orient => 'vertical', -command => [$tree, 'yview']);

$tree->g_grid(-row => 0, -column => 0, -sticky => "nsew");
$scrollbar->g_grid(-row => 0, -column => 1, -sticky => "ns");

$frm->g_grid_columnconfigure(0, -weight => 1);
$frm->g_grid_rowconfigure(0, -weight => 1);

$tree->configure(-yscrollcommand => [$scrollbar, 'set']);

Tkx::MainLoop();

Note that I'm still using pack to manage the parent frame and tell it to expand in both directions. If the parent frame doesn't expand the widgets within it can't either. I could have managed the frame with grid, but using pack is simpler.

Michael Carman
  • 30,628
  • 10
  • 74
  • 122