3
votes

I am trying to write a simple GUI for editing key-value pairs in TCL+Tk. It is based on a vertical ttk::panedwindow widget containing an arbitrary number of horizontal ttk::panedwindow widgets, each with a ttk::entry on the left side and a text widget on the right side. Below the main ttk::panedwindow is a frame containing buttons to do things like saving and loading files and adding new rows. This works fine, with all widgets scaling as I expect them to, but when more rows are added they get squeezed together or stretch the window.

Trying to make the window vertically scrollable didn't work properly. Tk is unfortunately very picky about what it will let me attatch scrollbars to, so I couldn't just put one on the main ttk::panedwindow. I tried various hacks listed on wiki.tcl.tk, but most of them use a canvas widget and scroll in both directions. If I remove the horizontal scrollbar, it won't be there anymore but the widgets will still extend beyond the edge of the window or stop before the edge of the window.

I also tried BWidget, but I didn't understand the relationship between the ScrolledWindow and ScrollableFrame widgets that I was told to use together. When I followed the examples they had the same problem as the canvas version. I suspect that they actually use a canvas internally rather than implementing a true scrollable frame.

How can I make the main interface scale to the dimensions of the window while also allowing vertical scrolling? I'm using Linux, if that helps.

I made a GIF to show what I want:

enter image description here

dissapearing scrollbar is optional, it just happened like that. The changing scribbles represent the lines of text adjusting to the available space.

1
Could you perhaps put pictures to demonstrate what you want to achieve?Jerry
I was thinking about that, but I'm not sure how to represent it with a static image... I'll try.Wutaz
You can use two (or more) images, add some arrows, writing on it is allowed too :)Jerry
I wrote a Virtual Scrolling Grid: wiki.tcl.tk/39411. It may help you do what you want.Brad Lanam

1 Answers

1
votes

So… you want the content to be “natural” in the vertical direction, yet stretched in the horizontal direction? Tricksy.

Your basic approach is going to be to put a frame (or ttk::frame) inside a canvas, put your “interesting” content inside the frame and add a scrollbar to the canvas. However, that's not the tricky bit. The tricky part is that you need to notice changes to the dimensions of the canvas and to the dimensions of the frame; a change to the frame should cause the adjustment of the canvas's bounding box, and a change to the canvas should cause adjustment to the requested width of the frame.

To notice a change to the size of any widget, you bind to the <Configure> event sent to that widget and use the %w and %h to get the width and height that the widget is being set to. (Indeed, geometry managers like grid and pack work exactly like that internally, except they use C-level bindings and not script-level ones.)

bind $canvas <Configure> {adjustCanvasDimensions %W %w %h}
bind $frame <Configure {adjustFrameDimensions %W %w %h}

proc adjustCanvasDimensions {theCanvas width height} {
    set theFrame $theCanvas.frame
    set oldwidth [$theFrame cget -width]
    if {$width != $oldwidth} {
        $theFrame configure -width $width
    }
    # Consider adjusting the frame height if canvas height greater
}
proc adjustFrameDimensions {theFrame width height} {
    set theCanvas [winfo parent $theFrame]
    $theCanvas configure -bbox [list 0 0 $width $height]
}

Or something like that. This is untested code (and assumes you put the frame in the canvas, etc.) but ought to show you the way forward.