0

I cannot get x and y scrollbars to work in Tkinter with Python, although I have followed multiple examples:

  1. How to add 2 scrollbars with tkinter in python 3.4
  2. Adding a scrollbar to a group of widgets in tkinter
  3. How to make a proper double scrollbar frame in tkinter
  4. Vertical and Horizontal Scrollbars on Tkinter Widget
  5. Scrolling a Canvas widget horizontally and vertically

The scrollbars appear, but do not activate when the window is smaller than the frame. How can I get this to work (see image below)?

Problem 1

Below is the minimal code that is producing my problem (Python 3.7)

import tkinter as tk from tkinter import ttk big_font = ("Arial", 50) class DoubleScrollbarFrame(ttk.Frame): def __init__(self, parent, *args, **kwargs): self.parent = parent super().__init__(self.parent, *args, **kwargs) #Set widgets to fill main window such that they are #all the same size self.columnconfigure(0, weight=1) self.rowconfigure(0, weight=1) self.create_widgets() self.position_widgets() def create_widgets(self): self.canvas = tk.Canvas(self) self.frame = ttk.Frame(self.canvas) self.scroll_x = ttk.Scrollbar(self, orient = tk.HORIZONTAL, command = self.canvas.xview) self.scroll_y = ttk.Scrollbar(self, orient = tk.VERTICAL, command = self.canvas.yview) self.canvas.config(xscrollcommand = self.scroll_x.set, yscrollcommand = self.scroll_y.set) self.canvas.create_window((0,0), window = self.frame, anchor = 'nw') self.frame.bind('<Configure>', self.set_scrollregion) self.sizegrip = ttk.Sizegrip(self) #Test self.test1 = tk.Label(self.frame, text = 'Test 1', font = big_font) self.test2 = tk.Label(self.frame, text = 'Test 2', font = big_font) self.test3 = tk.Label(self.frame, text = 'Test 3', font = big_font) def position_widgets(self, **kwargs): self.test1.grid(row = 0, column = 0, sticky = 'w') self.test2.grid(row = 1, column = 0, sticky = 'w') self.test3.grid(row = 2, column = 0, sticky = 'w') self.scroll_x.grid(row = 1, column = 0, sticky = 'ew') self.scroll_y.grid(row = 0, column = 1, sticky = 'ns') self.canvas.grid(row = 0, column = 0, sticky = 'nsew') self.frame.grid(row = 0, column = 0, sticky = 'nsew') self.sizegrip.grid(row = 1, column = 1, sticky = 'se') def set_scrollregion(self, event): print('Frame Dimensions: {} x {}'.format(self.frame.winfo_width(), self.frame.winfo_height())) print('Canvas Dimensions: {} x {}'.format(self.canvas.winfo_width(), self.canvas.winfo_height())) self.canvas.configure(scrollregion = self.canvas.bbox('all')) class MainApp(tk.Tk): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) #Set widgets to fill main window such that they are #all the same size self.columnconfigure(0, weight=1) self.rowconfigure(0, weight=1) self.create_widgets() self.position_widgets() def create_widgets(self): self.frame = DoubleScrollbarFrame(self) def position_widgets(self): self.frame.grid(row = 0, column = 0, sticky = 'nsew') def exit(self): self.destroy() if __name__ == '__main__': #Create GUI root = MainApp() #Run program root.mainloop() 
8
  • What have you done to debug this? For example, have you verified that the scrollregion is being updated to the correct values? Commented Jul 19, 2020 at 18:49
  • Please don't ask "bonus" questions - a good question asks about a single problem. Commented Jul 19, 2020 at 18:56
  • @BryanOakley I removed the bonus question, added references to links I've reviewed, and added a printout in set_scrollregion. The method only outputs: Frame Dimensions: 193 x 243 Canvas Dimensions: 1 x 1 and does not reprint when I resize the window. Commented Jul 19, 2020 at 20:36
  • You didn't answer the question of whether you've verified that scrollregion is being updated correctly. Commented Jul 19, 2020 at 21:31
  • @BryanOakley How do I verify scrollregion is updated correctly? Please tell me how to do this. Commented Jul 19, 2020 at 21:38

1 Answer 1

1

The problem is in these lines of code inside DoubleScrollbarFrame.position_widgets:

self.frame.grid(row = 0, column = 0, sticky = 'nsew') 

This removes control of the widget from the canvas and gives control to grid. It is no longer a canvas object, so self.canvas.bbox("all") is returning (0, 0, 1, 1). If the scrollregion is set incorrectly, the scrollbars don't know how much to scroll.

The solution is simple: don't call grid on self.frame.

Sign up to request clarification or add additional context in comments.

1 Comment

Brilliant! Thank you! This works perfectly now. I read Tkinter GUI Application Development Cookbook by Alejandro Rodas and he states "...we did not call any geometry manager to draw the frame because the create_window() method does this for us." I had no idea that calling the geometry manager would pass control from the canvas to the grid! I wish someone had mentioned this in a book or tutorial!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.