4

I'm using Python and Tkinter to create a GUI for a program I'm writing, and I'm having a couple of problems.

I have three objects descended from LabelFrame in an object descended from Frame. One of the LabelFrame descendants is two columns of corresponding Label and Entry objects.

freq_frame example

The problem is that there are a varying number of Label and Entry pairs, and there can be more than fit on the screen. I need a way to make a scrollbar for this LabelFrame so that everything fits on the screen. I've tried various ways of making a Scrollbar object, but nothing seems to work. How can I bind a scrollbar to this frame?

Also, I need to be able to refresh or reload this LabelFrame when the load_message() method is called, but it just redisplays the new pairs on top of the old ones (so when there are less pairs in the new set, the old set is still visible at the bottom). I've tried using grid_forget() but either nothing changes or the whole frame doesn't display. How can I forget this display and then redisplay it?

Here is the code for this class:

class freq_frame(LabelFrame):
    def __init__(self, master = None, text = 'Substitutions'):
        LabelFrame.__init__(self, master, text = text)
        self.grid()
    def load_message(self):
        self.frequency = get_freq(message)
        self.create_widgets()
    def create_widgets(self):
        self.label_list = [Label(self, text = get_label(char, self.frequency[char]), justify = LEFT) for char in self.frequency.keys()]
        self.entry_list = [Entry(self, width = 1) for char in self.frequency.keys()]
        for n in range(len(self.label_list)):
            self.label_list[n].grid(column = 0, row = n)
        for n in range(len(self.entry_list)):
            self.entry_list[n].grid(column = 1, row = n)

If anyone can help with either of these problems, I'd appreciate it.

Also, this question seems like it might be a little thin, but I don't know what to add. Don't hesitate to ask for more information (but be specific).

Thanks!

smackcrane
  • 1,379
  • 2
  • 10
  • 17

1 Answers1

4

Labelframes don't support scrolling. So the short answer to your question is "you can't". It sounds obvious, but if the documentation for a widget doesn't say it supports scrolling, it doesn't support scrolling.

However, there is a simple solution. First, add a canvas as a child to the labelframe and pack it so that it fills the labelframe. Attach scrollbars to the canvas and add them to the labelframe too. Then embed a frame within the canvas, add your widgets to that inner frame, and then adjust the scrollregion of the canvas to match the size of the frame after you've added all the inner labels and entries.

It sounds complicated, but it's really very straight-forward.

As for re-creating the widgets when you call load_message, calling grid_forget only removes them from view, it doesn't actually destroy the widgets. Over time you could potentially end up with hundreds of non-visible widgets which is almost certainly not what you want.

Instead, you want to first destroy all the existing widgets. That's pretty easy if they all are in the same parent, since you can ask the parent for a list of all its children. Just iterate over that list to delete each child, then add any new children. An even easier solution is to destroy and recreate that inner frame that contains the labels and entries. When you delete a widget, all child widgets get automatically destroyed. So, delete that inner frame, create a new one, and add your labels and entries again.

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • 1
    RE - "It sounds complicated": [Here is some example code](http://stackoverflow.com/questions/3085696/adding-a-scrollbar-to-a-grid-of-widgets-in-tkinter) that shows how to scroll a Frame that has a bunch of Label objects. I used this example successfully. The example code uses `pack` but I prefer `grid` so I successfully modified the code to use grid. – Trevor Boyd Smith Aug 26 '13 at 16:09
  • RE - "straight-forward": I find this code is only straight-forward if you have a complete understanding of all of the following: `Canvas`, `ScrollBar`, Tk's event handling, Tk's '' event, `Canvas`'s `bbox('all')` (the `'all'` parameter I was unable to find any documentation on after numerous google searches and consulting my textbook on Tkinter. where is the documentation on the 'all' parameter?) – Trevor Boyd Smith Aug 26 '13 at 16:12
  • @TrevorBoydSmith: where is "all" documented? Look at this page: http://effbot.org/tkinterbook/canvas.htm, then scroll down to the section titled "Item Specifiers: Handles and Tags". It mostly discusses the `ALL` constant, but that's just defined as the string `"all"`, which is also mentioned on that page. – Bryan Oakley Aug 26 '13 at 16:18
  • I was looking in the official www.tcl.tk documentation and didn't see any mention of the 'all' constant. Is the 'all' constant just for Python's tkinter? – Trevor Boyd Smith Aug 26 '13 at 17:51
  • 1
    @TrevorBoydSmith: This isn't just a Tkinter thing, it's part of the core tcl/tk implementation, and has been for a very long time. In the tcl/tk documentation it is on the canvas man page: http://www.tcl.tk/man/tcl8.5/TkCmd/canvas.htm#M22 – Bryan Oakley Aug 26 '13 at 19:44