There is a group of similar frames with some elements. I want to arrange these frames in the form of a column with a scrollbar on the right and pack the whole structure into one enclosing frame. I do this:

frame = Frame(mainWindow) # фрейм в котором будет расположен столбец фреймов с скроллом frame.grid() listbox = Listbox(dialogsFrame) listbox.pack(side = LEFT, fill = Y) scroll = Scrollbar(dialogsFrame) scroll.pack(side = RIGHT, fill = Y) listbox.config(yscrollcommand = scroll.set) scroll.config(command = listbox.yview) 

And then I pack my frames[i].grid(row = i, column = 0) in the listbox. The result is the desired design, but the scrollbar does not work. Those. there is no slider on it and it is not active at all. At the same time, by default, the frame size is sufficient so that there is no slider on the scrollbar (that is, all subframes are visible). When resizing the window to achieve the appearance of the slider fails. Scrollbar want to do because it is possible that there will be too many subframes and the window will come out of the monitor. How to do it?

Outside the original frame in the window can be located other elements. I would like to make the design independent of the size of these elements and the frame itself. Those. if the user resizes the window, then at a certain point (if the window height is too small) the scrollbar is activated. I just want to set a limit on the window itself (for example, set the height of the window to a certain fraction of the vertical resolution) and resize restrictions on some elements adjacent to the frame, and let the frame itself resize as it wants, only so that the scrollbar appears and works correctly.

UDP [02.26.2016]: found this example in stackoverflow English . Based on it, I made the following test code:

 from tkinter import * root = Tk() topButton = Button(root, text = 'Кнопка сверху') topButton.grid(row = 0, column = 0) lowFrame = Frame(root) lowFrame.grid(row = 1, column = 0) canvas = Canvas(lowFrame) frame = Frame(canvas) myscrollbar = Scrollbar(lowFrame, orient = 'vertical', command = canvas.yview) canvas.configure(yscrollcommand = myscrollbar.set) myscrollbar.pack(side = 'right', fill = Y) canvas.pack(side = 'left') canvas.create_window((0, 0), window = frame, anchor = 'nw') def conf(event): canvas.configure(scrollregion = canvas.bbox('all')) frame.bind('<Configure>', conf) for i in range(50): b = Button(frame, text = str(i)) b.grid(row = i, column = 0) root.mainloop() 

It works fine, but a couple of questions arose:

  1. What does canvas.create_window() do? What is this window where it is created?
  2. We bind the frame.bind('<Configure>', conf) . You can check that the event occurs every time you use the scroll. Why does a frame-related event occur when using a scroll?
  3. What does this thing do: canvas.configure(scrollregion = canvas.bbox('all')) ? Why does it need to be executed every time it is scrolled, why is it not enough to execute it once when the program is initialized?
  4. Is there no way to bind an event (see 2 and 3) without explicitly defining an additional function in the program? Use lambda expressions, or something like that?
  • I think the listbox is nowhere. You just need to take the scrollbar and screw it correctly. - insolor
  • I redid this example: effbot.org/tkinterbook/scrollbar.htm - hunter
  • And here ( effbot.org/tkinterbook/scrollbar.htm ) is also indicated that the scroll is only screwed to the listbox. Text, Entry for text, Canvas in general for images. - hunter
  • It says that the Scrollbar is almost always used with the Listbox, Canvas, or TextBox. In itself, this proposal does not deny the possibility of using the Scrollbar separately from them, or in some other way (for example, with the frame, although it will not be so convenient). When used with a Listbox, the state of a Scrollbar depends on the text strings added to it, and not the controls attached to it. - insolor

1 answer 1

  1. The canvas.create_window() method is needed to place the widget (in this case, the frame) on the canvas object.
  2. The <Configure> event is triggered when the widget is resized and positioned (in this case, the frame widget), apparently including when scrolling. See Events and Bindings .
  3. canvas.configure(scrollregion = ...) sets a scrollable (scrollable) rectangle inside the canvas . In this case, this is canvas.bbox('all') (bbox - bounding box is a bounding box, i.e., a rectangle that contains all the content), 'all' is a tag that is attached to all elements on the canvas - shapes and widgets (see Item Specifiers: Handles and Tags ).
    • This action is needed to set the canvas scrollable area based on the size of the frame placed on the canvas . The frame gets its final size after all the buttons are actually added, and it seems that this happens already during the execution of mainloop() . You can replace this repeated action with the string root.after(100, lambda: canvas.configure(scrollregion = canvas.bbox('all'))) , but it’s safer to do it by binding to the <Config> event (especially if you are the process of the program will add widgets to the frame)
  4. frame.bind('<Configure>', lambda event: canvas.configure(scrollregion = canvas.bbox('all')))