简体   繁体   English

Tkinter 带网格的滚动条:滚动过去的帧和滚动条灰色

[英]Tkinter Scrollbar with Grid: Scrolls past frame and scrollbar gray

I'm trying to implement a scrollbar into my Python program with Tkinter.我正在尝试使用 Tkinter 在我的 Python 程序中实现滚动条。 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.在使用我不能/不想使用的 .pack 方法之前回答的大多数问题。 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.此外,在大多数示例中,对象被添加到滚动条代码所在的同一 scope 中的框架中,但我想通过 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()

How can I "activate" the scrollbar?如何“激活”滚动条? How can I limit the scrolling to the first and last element in the frame?如何将滚动限制到框架中的第一个和最后一个元素?

You have the <Configure> event bound to the Canvas, when it should be bound to the Frame.您将<Configure>事件绑定到 Canvas,它应该绑定到 Frame。 You also need to move that into build_widgets method.您还需要将其移至 build_widgets 方法中。

For cleanliness sake, I also recommend you move away from lambda and into a real method.为了清洁起见,我还建议您远离 lambda 并采用真正的方法。 So add this to end of build_widgets:因此,将其添加到 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"))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM