Python 带网格的Tkinter滚动条:滚动超过帧,滚动条为灰色

Python 带网格的Tkinter滚动条:滚动超过帧,滚动条为灰色,python,tkinter,scrollbar,Python,Tkinter,Scrollbar,我正试图用Tkinter在Python程序中实现一个滚动条。问题是滚动条可能会在框架顶部上方和底部下方滚动。此外,滚动条看起来已停用,即使按钮和鼠标滚轮可以工作 在使用.pack方法之前回答的大多数问题,我不能/不想使用。此外,在大多数示例中,对象被添加到scrollbar代码所在的相同范围内的帧中,但我希望通过loadColumnNames方法来实现 import tkinter as tk from tkinter import ttk from tkinter import fil

我正试图用Tkinter在Python程序中实现一个滚动条。问题是滚动条可能会在框架顶部上方和底部下方滚动。此外,滚动条看起来已停用,即使按钮和鼠标滚轮可以工作

在使用.pack方法之前回答的大多数问题,我不能/不想使用。此外,在大多数示例中,对象被添加到scrollbar代码所在的相同范围内的帧中,但我希望通过loadColumnNames方法来实现

    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()
将tkinter作为tk导入
从tkinter导入ttk
从tkinter导入文件对话框
类主窗口(tk.Frame):
def构建_小部件(自):
#创建一个笔记本,以便以后将选项卡嵌入其中。
self.nb=ttk.笔记本(self)
self.nb.grid(行=1,列=0,列span=5,行span=5,sticky=“NESW”)
tabStyle=ttk.Style()
tabStyle.configure(“new.TFrame”,background=“white”)
#---------------------------------------------------
#列重命名选项卡。
#---------------------------------------------------
tab2=ttk.Frame(self.nb,style=“New.TFrame”)
self.nb.add(tab2,text=“列重命名”)
框架=传统框架(表2)
frame.grid(行=1,列=2,sticky=“nesw”)
button=tk.button(frame,text=“加载列名”,command=self.loadColumnNames)
button.grid(行=1,列=0,sticky=“nesw”,padx=self.padlight)
wrapperFrame=tk.LabelFrame(表2)
self.columnNamesCanvas=tk.Canvas(包装框架)
self.columnNamesCanvas.grid(行=0,列=0,sticky=“nesw”)
yscrollbar=ttk.Scrollbar(wrapperFrame,orient=“vertical”,command=self.columnNamesCanvas.yview)
yscrollbar.grid(行=0,列=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(行=1,列=1,sticky=“nesw”)
self.columnNamesFrame.bind(“,self.\u绑定到\u鼠标滚轮)
self.columnNamesFrame.bind(“,self.\u未绑定到\u鼠标滚轮)
返回
def uuu init uuu(self,master=None):
self.PadLeft=10
self.columnsframevars={}
tk.Frame.\uuuuu init\uuuuuu(self,master,bg=bg)
self.pack()
self.build_widgets()
返回
定义绑定到鼠标滚轮(自身、事件):
self.columnNamesCanvas.bind_all(“,self._在鼠标滚轮上)
def_解除与鼠标滚轮的绑定(自身、事件):
self.columnNamesCanvas.unbind_all(“”)
鼠标滚轮上的def(自身、事件):
self.columnNamesCanvas.yview_滚动条(int(-1*(event.delta/120)),“单位”)
def loadColumnNames(自身):
self.columnsframevars={}
列=[“a”、“b”、“c”、“d”、“e”、“f”、“h”、“i”、“j”、“k”、“l”、“m”、“n”]
i=0
对于列中的列:
self.columNamesFrameVars[column]=[]
#新列名。
newname=tk.Entry(self.columnNamesFrame)
网格(行=i,列=3,padx=self.PadLeft)
newname.insert(0,str(列))
self.columNamesFrameVars[column].append(newname)
i+=1
self.columnNamesCanvas.bind(“”,lambda e:self.columnNamesCanvas.configure(scrollregion=self.columnNamesCanvas.bbox(“全部”))
返回
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
BG=“白色”
root=tk.tk()
root.wm_标题(“”)
主窗口(根)
root.mainloop()
如何“激活”滚动条?如何将滚动限制到帧中的第一个和最后一个元素?

您将
事件绑定到画布,而此时它应该绑定到帧。您还需要将其转移到build_widgets方法中

为了清洁起见,我还建议您远离lambda,转而使用真正的方法。因此,将此添加到构建结束小部件:

self.columnNamesFrame.bind('<Configure>', self._on_configure)
#     ^ note this is the Frame, not the Canvas
您将
事件绑定到画布,而此时它应该绑定到框架。您还需要将其转移到build_widgets方法中

为了清洁起见,我还建议您远离lambda,转而使用真正的方法。因此,将此添加到构建结束小部件:

self.columnNamesFrame.bind('<Configure>', self._on_configure)
#     ^ note this is the Frame, not the Canvas

请尝试将此代码缩减为一个。如果您可以添加一些硬编码数据,而不是依赖外部csv文件,这也是最好的选择。请尝试移动
columnNamesCanvas.bind(“
行进入
build\u widgets
方法。@Novel将该行移动到
build\u widgets
方法中只会使情况更糟:我仍然可以滚动到帧中第一个元素的上方,但无法滚动到第十个元素下方的元素太糟糕了,这只是一个猜测。好吧,我们需要看a来进一步帮助您。@Novel我已经减少了我的示例代码。谢谢。请尝试将此代码缩减为。如果您可以添加一些硬编码数据,而不是依赖外部csv文件,这也是最好的。请尝试移动
columnNamesCanvas.bind(“
行进入
build\u widgets
方法。@Novel将该行移动到
build\u widgets
方法中只会使情况更糟:我仍然可以滚动到帧中第一个元素的上方,但无法滚动到第十个元素下方的元素太糟糕了,这只是一个猜测。好吧,我们需要看a来进一步帮助您。@Novel我已经减少了我的示例代码。谢谢。我想在
build\u widget
方法中有几个滚动条。是否可以为画布的
\on\u configure
添加参数?如果可以,我如何在
bind()中传递画布参数
method?@Nick当然,你会使用
functools.partial
方法来创建一个要绑定的闭包。但我怀疑,如果有一个抽象滚动条、框架、画布等的子类,并多次使用该子类会更好。很多人都创建了滚动条类,包括我:我想