0

I used a scrollbar for my tkinter app with Canvas. I am using Pack to set up the scrollbars. But I have a problem. The horizontal scrollbar works fine, but the vertical scrollbar does not. The location is misconfigured.

My code:

    self.scroll_x = tk.Scrollbar(self, orient=tk.HORIZONTAL)
    self.scroll_y = tk.Scrollbar(self, orient=tk.VERTICAL)
    self.canvas = tk.Canvas(self, width=600, height=100,
    xscrollcommand=self.scroll_x.set,
    yscrollcommand=self.scroll_y.set)
    self.scroll_x.config(command=self.canvas.xview)
    self.scroll_y.config(command=self.canvas.yview)
    self.frame = tk.Frame(self.canvas)

     self.canvas.create_window((0, 0), window=self.frame,anchor=tk.NW)
     self.canvas.bind_all("<MouseWheel>", self.on_mousewheel)
     self.canvas.config(scrollregion=self.canvas.bbox(tk.ALL))
     self.canvas.pack(side=tk.LEFT,expand=True,fill=tk.BOTH)
     self.scroll_x.pack(side=tk.BOTTOM,fill=tk.X)
     self.scroll_y.pack(side=tk.RIGHT,fill=tk.Y)
     self.bind("<Configure>", self.resize)
            
     self.update_idletasks()

def on_mousewheel(self, event):
    shift = (event.state & 0x1) != 0
    scroll = -1 if event.delta > 0 else 1
    if shift:
        self.canvas.xview_scroll(scroll, "units")
    else:
        self.canvas.yview_scroll(scroll, "units")

def resize(self, event):
    region = self.canvas.bbox(tk.ALL)
    self.canvas.configure(scrollregion=region)
  • The horizontal scrollbar is misconfigured. self.scrollbox = tk.Scrollbar (self, orient = tk.HORIZONTAL) self.scroll_x.pack (side = tk.BOTTOM, fill = tk.X) –  Sep 17 '20 at 18:40

1 Answers1

0

I recommand using grid in this case. See more

import tkinter as tk

class MyFigure(tk.Frame):
    def __init__(self, master):
        tk.Frame.__init__(self, master)
        
        self.scroll_x = tk.Scrollbar(self, orient=tk.HORIZONTAL)
        self.scroll_y = tk.Scrollbar(self, orient=tk.VERTICAL)
        self.canvas = tk.Canvas(self, width=600, height=100, bg='red',
                                xscrollcommand=self.scroll_x.set,
                                yscrollcommand=self.scroll_y.set)
        self.scroll_x.config(command=self.canvas.xview)
        self.scroll_y.config(command=self.canvas.yview)
        self.frame = tk.Frame(self.canvas)
        self.canvas.create_window((0, 0), window=self.frame,anchor=tk.NW)
        self.canvas.bind_all("<MouseWheel>", self.on_mousewheel)
        self.canvas.config(scrollregion=self.canvas.bbox(tk.ALL))
        
        self.canvas.grid(column=0,row=0)
        self.scroll_x.grid(column=0,row=1,sticky='ew')
        self.scroll_y.grid(column=1,row=0,sticky='ns')
        self.bind("<Configure>", self.resize)

    def on_mousewheel(self, event):
        shift = (event.state & 0x1) != 0
        scroll = -1 if event.delta > 0 else 1
        if shift:
            self.canvas.xview_scroll(scroll, "units")
        else:
            self.canvas.yview_scroll(scroll, "units")

    def resize(self, event):
        region = self.canvas.bbox(tk.ALL)
        self.canvas.configure(scrollregion=region)

root = tk.Tk()
mf = MyFigure(root)
mf.pack()
root.mainloop()

If you really need to use pack, than be aware that by using it in a complex way the order of packing the widgets is important. I think its easier to order the rest of your frame with grid instead trying to pack them together.

Anyway, replace these lines in the above code and it works:

self.scroll_x.pack(side=tk.BOTTOM,fill=tk.X)
self.canvas.pack(side=tk.LEFT,expand=True,fill=tk.BOTH)
self.scroll_y.pack(side=tk.LEFT,fill=tk.Y)
Thingamabobs
  • 7,274
  • 5
  • 21
  • 54
  • Thank you for your reply. I can't use grid, because I use pack elsewhere in the class I use pack. –  Sep 17 '20 at 19:09
  • 1
    @Jena: you can create a frame with just the canvas and scrollbars and use grid inside it, while still using pack to add the frame to the rest of the UI – Bryan Oakley Sep 17 '20 at 19:18
  • True. In each master(window/frame) you can choose which manager you want to use. Let me know if its an option for you. – Thingamabobs Sep 17 '20 at 19:21