Reputation: 49
I'm trying to implement a scrollbar into my Python program with Tkinter. The problem is that the scrollbar can scroll above the top and below the bottom of the frame. Moreover, the scrollbar looks deactivated, even though the buttons and mouse wheel work.
Most questions answered before use the .pack method, which I can't/don't want to use. Moreover, in most examples the objects are added to the frame in the same scope where the scrollbar code is, but I want to do that through the loadColumnNames method instead.
import tkinter as tk
from tkinter import ttk
from tkinter import filedialog
class MainWindow(tk.Frame):
def build_widgets(self):
# Create a notebook to later embed the tabs into it.
self.nb = ttk.Notebook(self)
self.nb.grid(row=1, column=0, columnspan=5, rowspan=5, sticky="NESW")
tabStyle = ttk.Style()
tabStyle.configure("new.TFrame", background="white")
#---------------------------------------------------
# Column renaming tab.
#---------------------------------------------------
tab2 = ttk.Frame(self.nb, style="New.TFrame")
self.nb.add(tab2, text="Column Renaming")
frame = tk.Frame(tab2)
frame.grid(row=1, column=2, sticky="nesw")
button = tk.Button(frame, text="Load Column Names", command=self.loadColumnNames)
button.grid(row=1, column=0, sticky="nesw", padx=self.PadLeft)
wrapperFrame = tk.LabelFrame(tab2)
self.columnNamesCanvas = tk.Canvas(wrapperFrame)
self.columnNamesCanvas.grid(row=0, column=0, sticky="nesw")
yscrollbar = ttk.Scrollbar(wrapperFrame, orient="vertical", command=self.columnNamesCanvas.yview)
yscrollbar.grid(row=0, column=4, sticky="ns")
self.columnNamesCanvas.configure(yscrollcommand=yscrollbar.set)
self.columnNamesFrame = tk.Frame(self.columnNamesCanvas)
self.columnNamesCanvas.create_window((0,0), window=self.columnNamesFrame, anchor="nw")
wrapperFrame.grid(row=1, column=1, sticky="nesw")
self.columnNamesFrame.bind("<Enter>", self._bound_to_mousewheel)
self.columnNamesFrame.bind("<Leave>", self._unbound_to_mousewheel)
return
def __init__(self, master=None):
self.PadLeft = 10
self.columNamesFrameVars = {}
tk.Frame.__init__(self, master, bg=BG)
self.pack()
self.build_widgets()
return
def _bound_to_mousewheel(self, event):
self.columnNamesCanvas.bind_all("<MouseWheel>", self._on_mousewheel)
def _unbound_to_mousewheel(self, event):
self.columnNamesCanvas.unbind_all("<MouseWheel>")
def _on_mousewheel(self, event):
self.columnNamesCanvas.yview_scroll(int(-1*(event.delta/120)), "units")
def loadColumnNames(self):
self.columNamesFrameVars = {}
columns = ["a", "b", "c", "d", "e", "f", "h", "i", "j", "k", "l", "m", "n"]
i = 0
for column in columns:
self.columNamesFrameVars[column] = []
# New column name.
newname = tk.Entry(self.columnNamesFrame)
newname.grid(row=i, column=3, padx=self.PadLeft)
newname.insert(0, str(column))
self.columNamesFrameVars[column].append(newname)
i += 1
self.columnNamesCanvas.bind('<Configure>', lambda e: self.columnNamesCanvas.configure(scrollregion = self.columnNamesCanvas.bbox("all")))
return
if __name__ == '__main__':
BG = "white"
root = tk.Tk()
root.wm_title("")
MainWindow(root)
root.mainloop()
How can I "activate" the scrollbar? How can I limit the scrolling to the first and last element in the frame?
Upvotes: 0
Views: 322
Reputation: 13729
You have the <Configure>
event bound to the Canvas, when it should be bound to the Frame. You also need to move that into build_widgets method.
For cleanliness sake, I also recommend you move away from lambda and into a real method. So add this to end of build_widgets:
self.columnNamesFrame.bind('<Configure>', self._on_configure)
# ^ note this is the Frame, not the Canvas
And add this method:
def _on_configure(self, event=None):
self.columnNamesCanvas.configure(scrollregion = self.columnNamesCanvas.bbox("all"))
Upvotes: 2