here is my code, I checked few other questions about scrollbar with tkinter, and still can not figure out why my devices (button in the frame inside a canvas can not scroll)
the scroll bar and canvas seems get the configure event, and also scrollbar and canvas yview got called correctly, but the frame inside not scroll with it. Did I missing something ?
import tkinter as tk
import tkinter.font as tkFont
from tkinter import StringVar
c20 = None
c16 = None
class DebugScrollbar(tk.Scrollbar):
def set(self, *args):
print ("SCROLLBAR SET", args)
tk.Scrollbar.set(self, *args)
class DebugCanvas(tk.Canvas):
def yview(self, *args):
print("Canvas yview" , args)
tk.Canvas.yview(self, *args)
class Application:
def __init__(self):
master = tk.Tk()
global c20, c16
c20 = tkFont.Font( family ='Helvetica', size = 20)
c18 = tkFont.Font( family ='Helvetica', size = 18)
c12 = tkFont.Font( family ='Helvetica', size = 12)
self.c16 = c16 = tkFont.Font( family ='Helvetica', size = 16)
self.myIp = tk.StringVar()
self.master = master
master.option_add('*Font', c18)
self.c20 = c20
self.c24 = tkFont.Font( family='Helvetica', size=24)
##self._geom='200x200+0+0'
##master.geometry("{0}x{1}+0+0".format( master.winfo_screenwidth()-pad, master.winfo_screenheight()-pad))
master.title("Safe Home")
#master.attributes("-fullscreen", True)
self.topBar = tk.Frame(master)
self.topBar.grid(columnspan=5, sticky=tk.N)
self.wifiStatus = tk.StringVar()
self.wifiStatus.set("WIFI1 %d" )
self.wifi = tk.Label(self.topBar, textvariable= self.wifiStatus, borderwidth=2, relief="ridge", height=4, width=8)
self.wifi.grid(sticky=tk.E, row=1, column = 0 , padx=3, pady=3)
self.mainFrame = tk.Frame(self.master, relief=tk.GROOVE, bd=1)
self.mainFrame.grid(row=2, column=0 , columnspan=5 , rowspan=3, padx=3, pady=3)
self.prepareDevices(self.mainFrame)
self.devices.pack( side= tk.LEFT, padx=3, pady=3 )
#self.greet_button["font"]=c20
self.close_button = tk.Button(master, text="Close", command=master.quit)
self.close_button.grid(columnspan=1, sticky=tk.SE, row=6, column=4 )
#self.close_button["font"]=c20
self.addDevices(self.devices)
def prepareDevices(self, insideFrame):
insideFrame.grid_rowconfigure(0, weight=1)
insideFrame.grid_columnconfigure(0, weight=1)
vscrollbar = DebugScrollbar( insideFrame, orient=tk.VERTICAL)
vscrollbar.grid(row=0, column=1, sticky=tk.N+tk.S)
self.canvas = canvas = DebugCanvas( insideFrame, background = "#D2D2D2",# bd=1, relief='solid', highlightthickness=1,
#scrollregion=(0, 0, 1000, 1000),
yscrollcommand=vscrollbar.set)
vscrollbar.config(command = canvas.yview)
canvas.config( yscrollcommand = vscrollbar.set )
canvas.config(width = 100, height = 280)
canvas.grid(row=0, column=0, sticky=tk.N+tk.S+tk.E+tk.W)
vscrollbar.config(command = canvas.yview)
canvas.config( yscrollcommand = vscrollbar.set )
# reset the view
#canvas.xview_moveto(0)
#canvas.yview_moveto(0)
# create a frame inside the canvas which will be scrolled with it
self.devices = interior = tk.Frame(canvas #, bd=2 , relief='groove'
)
interior_id = canvas.create_window(0, 0, window=interior, anchor=tk.NW)
def _configure_interior(event):
# update the scrollbars to match the size of the inner frame
print("Configure interior event: %s" % (event))
size = (interior.winfo_reqwidth(), interior.winfo_reqheight())
sizeStr= "0 0 %s %s" % size
print(sizeStr)
canvas.config( scrollregion = (0,0, interior.winfo_reqwidth(), interior.winfo_reqheight()) )
print ("canvas adjust region")
if interior.winfo_reqwidth() != canvas.winfo_width():
# update the canvas's width to fit the inner frame
canvas.config(width=interior.winfo_reqwidth())
canvas.config(width= 180, height = 280)
interior.bind('<Configure>', _configure_interior)
def _configure_canvas(event):
##
print("Configure canvas %s" % (event))
if interior.winfo_reqwidth() != canvas.winfo_width():
# update the inner frame's width to fill the canvas
canvas.itemconfigure(interior_id, width=canvas.winfo_width())
print ("canvas adjust width")
canvas.bind('<Configure>', _configure_canvas)
# track changes to the canvas and frame width and sync them,
# also updating the scrollbar
def addDevices(self, deviceFrame):
for i in range(1 , 20):
d = Device("1D:1s:%d" % i)
l = DeviceLabel(deviceFrame, name="device %s" % i, macAddress=d.macAddress, mainWindow = self)
class Device():
def __init__(self, macAddress):
self.macAddress = macAddress
pass
class DeviceLabel( ):
def __init__(self, parent, name, mainWindow, macAddress = None, status=None):
global c16
self.text = tk.StringVar()
self.label= tk.Button( parent, textvariable = self.text, bd=1, relief="groove", height=3, width=15, command = lambda: mainWindow.deviceDetail(macAddress))
self.macAddress = macAddress
self.status = status
self.name = name
self.text.set(name)
self.label["font"] = c16
self.label.pack()
my_gui = Application()
my_gui.master.mainloop()
def, putglobalas first line in method, etc. It makes code more readable. - furas