tkinter滚动画布无法滚动框架insde

时间:2018-01-13 05:31:49

标签: python canvas tkinter scrollbar

这是我的代码,我检查了有关滚动条与tkinter的其他几个问题,但仍然无法弄清楚为什么我的设备(画布内的框架中的按钮无法滚动)

滚动条和画布似乎得到了配置事件,并且滚动条和画布yview被正确调用,但内部框架没有滚动它。 我错过了什么吗?

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()

1 个答案:

答案 0 :(得分:3)

内部Frameself.devices)是Canvas上的元素,不是外部框架的一部分,也不是任何其他窗口小部件/窗口,所以你不应该这样做

self.devices.pack(side=tk.LEFT, padx=3, pady=3)

删除此行,它将正常工作。