如何在 python 中访问函数外部的框架

How to access the frame outside the function in python

如何在函数外部访问 scroll_frame,以便 new_frame 位于下面代码中的 scroll_frame 内部。

def scroll():
    container = LabelFrame(root)

    my_canvas = Canvas(container)
    my_canvas.pack(side=LEFT, fill=BOTH, expand=1)

    scroll_y = Scrollbar(container, orient=VERTICAL, command=my_canvas.yview)
    scroll_y.pack(side=RIGHT, fill='y')

    my_canvas.configure(yscrollcommand=scroll_y.set)
    my_canvas.bind('<Configure>', lambda e: my_canvas.configure(scrollregion=my_canvas.bbox('all')))

    scroll_frame = Frame(my_canvas)
    my_canvas.create_window((0, 0), window=scroll_frame, anchor=NW)

    container.pack(fill=BOTH, expand=1)


new_frame = Frame(scroll_frame)

for i in range(25):
    Button(new_frame, text='click'+str(i)).pack()

scroll()

root.mainloop()

如果您想访问 scroll_frame,您应该从 scroll().

return

也建议return container不要在scroll()里面调用container.pack(...)因为这样比较灵活

还建议将父级也传递给 scroll(),而不是在其中硬编码 root

from tkinter import *

def scroll(parent):
    container = LabelFrame(parent)

    my_canvas = Canvas(container, highlightthickness=0)
    my_canvas.pack(side=LEFT, fill=BOTH, expand=1)

    scroll_y = Scrollbar(container, orient=VERTICAL, command=my_canvas.yview)
    scroll_y.pack(side=RIGHT, fill=Y)

    my_canvas.configure(yscrollcommand=scroll_y.set)

    scroll_frame = Frame(my_canvas)
    my_canvas.create_window((0, 0), window=scroll_frame, anchor=NW)

    # bind <Configure> on scroll_frame instead of my_canvas
    scroll_frame.bind('<Configure>', lambda e: my_canvas.configure(scrollregion=my_canvas.bbox('all')))

    return container, scroll_frame

root = Tk()

container, scroll_frame = scroll(root)
container.pack(fill=BOTH, expand=1)

# Is new_frame necessary? Why not use scroll_frame directly?
new_frame = Frame(scroll_frame)
new_frame.pack()

for i in range(25):
    Button(new_frame, text='click'+str(i)).pack(fill=X)

root.mainloop()

注意,如果要重复使用scroll(),最好使用class而不是函数。


更新:使用 class 实现:

import tkinter as tk

class ScrollableFrame(tk.LabelFrame):
    def __init__(self, parent, **kw):
        super().__init__(parent, **kw)

        canvas = tk.Canvas(self, highlightthickness=0)
        canvas.pack(side="left", fill="both", expand=1)

        vscrollbar = tk.Scrollbar(self, orient="vertical", command=canvas.yview)
        vscrollbar.pack(side="right", fill="y")
        canvas.config(yscrollcommand=vscrollbar.set)

        self.scroll_frame = tk.Frame(canvas)
        self.scroll_frame.bind("<Configure>", lambda e: canvas.config(scrollregion=canvas.bbox("all")))
        canvas.create_window(0, 0, window=self.scroll_frame, anchor="nw")

if __name__ == "__main__":
    root = tk.Tk()
    container = ScrollableFrame(root)
    container.pack(fill="both", expand=1)
    for i in range(25):
        tk.Button(container.scroll_frame, text=f"click {i}").pack(fill="x")
    root.mainloop()

@acw1668 的解决方案很好,但我无法在我想要的框架中制作滚动条。

所以最后我得出了这个:

from tkinter import * # you should avoid wildcard import

root = Tk()

f1 = Frame(root)
t1 = Text(root)

f2 = Frame(root)
t2 = Text(root)

def scroll(in_frame, lbl, txt):
    in_frame_lbl = Label(in_frame, text=lbl)
    in_frame_lbl.pack(fill=X)
    in_frame.pack(fill=X)

    scroll_y = Scrollbar(in_frame, orient=VERTICAL)
    scroll_y.pack(side=RIGHT, anchor=N, fill=Y)

    txt.config(yscrollcommand=scroll_y.set)
    txt.pack(fill=X)
    scroll_y.config(command=txt.yview)
    txt.config(state='disabled')

scroll(f1, 'Scroll in Frame 1', t1)
scroll(f2, 'Scroll in Frame 2', t2)

for i in range(5):
    Button(f1, text='click'+str(i)).pack(fill=X)
    Entry(f2).pack()

root.mainloop()