Tkinter 在可滚动框架上添加小部件最后一项未显示
Tkinter add widget on scroolable frame last item does not shown
我想创建一个 window 允许为文件传输输入一对多字段。
我创建了一个 Scrollable Frame 并在运行时添加了 Entry-Text 对。如果我第一次点击按钮,一切顺利。第二次之后,UI 端没有任何反应。第二次单击后它可以完美运行。但是我看到所有的pair都添加成功了,只是UI没有显示出来。有人知道如何解决吗?
import tkinter as tk
class VerticalScroolFrame(tk.Frame):
"""A frame with a vertical scroolbar"""
def __init__(self, master, *args, **kwargs):
main_frame = tk.Frame(master)
main_frame.grid()
main_frame.rowconfigure(0, weight=1)
main_frame.columnconfigure(0, weight=1)
self._canvas = tk.Canvas(main_frame)
self._canvas.grid(row=0, column=0, sticky=tk.NSEW)
scrollbar = tk.Scrollbar(main_frame, command=self._canvas.yview)
scrollbar.grid(row=0, column=1, sticky=tk.N+tk.S+tk.W)
self._canvas.configure(yscrollcommand=scrollbar.set)
self._canvas.bind('<Configure>', lambda *_: self.on_configure())
super().__init__(self._canvas, *args, **kwargs)
self._canvas.create_window((0, 0), window=self, anchor=tk.NW)
def on_configure(self):
"""update scrollregion after starting 'mainloop'
when all widgets are in self._canvas. And also need to be triggered
whenever a widget added as a child.
"""
self._canvas.configure(scrollregion=self._canvas.bbox('all'))
class AdvancedTransfer:
"""Opens a window that allows you to enter source file list
and targets for them. One-to-many relation.
"""
def __init__(self, root):
self._scroolable_frame = VerticalScroolFrame(root)
self._entry_text_dict = {}
self._button = tk.Button(root, text="Add", command=self.add_item)
self._button.grid()
def add_item(self):
"""Add entry-text widget group"""
row = len(self._entry_text_dict)
entry = tk.Entry(self._scroolable_frame)
entry.insert(0, "row number: {0}".format(row))
entry.grid(row=row, column=0)
text = tk.Text(self._scroolable_frame)
text.grid(row=row, column=1)
self._entry_text_dict[entry] = text
self._scroolable_frame.on_configure()
def main():
root = tk.Tk()
main_frame = tk.Frame(root)
main_frame.grid()
AdvancedTransfer(main_frame)
root.mainloop()
if __name__ == "__main__":
main()
重现步骤:
- 运行下面的代码。
- 点击按钮两次。
- 您应该看到 2 对,但只显示了 1 对。
这是因为您在错误的小部件上绑定了 <Configure>
事件。您应该绑定到内部框架(即 VerticalScroolFrame
的实例)而不是 canvas (self._canvas
):
class VerticalScroolFrame(tk.Frame):
"""A frame with a vertical scroolbar"""
def __init__(self, master, *args, **kwargs):
main_frame = tk.Frame(master)
main_frame.grid()
main_frame.rowconfigure(0, weight=1)
main_frame.columnconfigure(0, weight=1)
self._canvas = tk.Canvas(main_frame)
self._canvas.grid(row=0, column=0, sticky=tk.NSEW)
scrollbar = tk.Scrollbar(main_frame, command=self._canvas.yview)
scrollbar.grid(row=0, column=1, sticky=tk.N+tk.S+tk.W)
self._canvas.configure(yscrollcommand=scrollbar.set)
#self._canvas.bind('<Configure>', lambda *_: self.on_configure())
super().__init__(self._canvas, *args, **kwargs)
self._canvas.create_window((0, 0), window=self, anchor=tk.NW)
# bind <Configure> event on itself
self.bind('<Configure>', lambda _: self.on_configure())
我想创建一个 window 允许为文件传输输入一对多字段。 我创建了一个 Scrollable Frame 并在运行时添加了 Entry-Text 对。如果我第一次点击按钮,一切顺利。第二次之后,UI 端没有任何反应。第二次单击后它可以完美运行。但是我看到所有的pair都添加成功了,只是UI没有显示出来。有人知道如何解决吗?
import tkinter as tk
class VerticalScroolFrame(tk.Frame):
"""A frame with a vertical scroolbar"""
def __init__(self, master, *args, **kwargs):
main_frame = tk.Frame(master)
main_frame.grid()
main_frame.rowconfigure(0, weight=1)
main_frame.columnconfigure(0, weight=1)
self._canvas = tk.Canvas(main_frame)
self._canvas.grid(row=0, column=0, sticky=tk.NSEW)
scrollbar = tk.Scrollbar(main_frame, command=self._canvas.yview)
scrollbar.grid(row=0, column=1, sticky=tk.N+tk.S+tk.W)
self._canvas.configure(yscrollcommand=scrollbar.set)
self._canvas.bind('<Configure>', lambda *_: self.on_configure())
super().__init__(self._canvas, *args, **kwargs)
self._canvas.create_window((0, 0), window=self, anchor=tk.NW)
def on_configure(self):
"""update scrollregion after starting 'mainloop'
when all widgets are in self._canvas. And also need to be triggered
whenever a widget added as a child.
"""
self._canvas.configure(scrollregion=self._canvas.bbox('all'))
class AdvancedTransfer:
"""Opens a window that allows you to enter source file list
and targets for them. One-to-many relation.
"""
def __init__(self, root):
self._scroolable_frame = VerticalScroolFrame(root)
self._entry_text_dict = {}
self._button = tk.Button(root, text="Add", command=self.add_item)
self._button.grid()
def add_item(self):
"""Add entry-text widget group"""
row = len(self._entry_text_dict)
entry = tk.Entry(self._scroolable_frame)
entry.insert(0, "row number: {0}".format(row))
entry.grid(row=row, column=0)
text = tk.Text(self._scroolable_frame)
text.grid(row=row, column=1)
self._entry_text_dict[entry] = text
self._scroolable_frame.on_configure()
def main():
root = tk.Tk()
main_frame = tk.Frame(root)
main_frame.grid()
AdvancedTransfer(main_frame)
root.mainloop()
if __name__ == "__main__":
main()
重现步骤:
- 运行下面的代码。
- 点击按钮两次。
- 您应该看到 2 对,但只显示了 1 对。
这是因为您在错误的小部件上绑定了 <Configure>
事件。您应该绑定到内部框架(即 VerticalScroolFrame
的实例)而不是 canvas (self._canvas
):
class VerticalScroolFrame(tk.Frame):
"""A frame with a vertical scroolbar"""
def __init__(self, master, *args, **kwargs):
main_frame = tk.Frame(master)
main_frame.grid()
main_frame.rowconfigure(0, weight=1)
main_frame.columnconfigure(0, weight=1)
self._canvas = tk.Canvas(main_frame)
self._canvas.grid(row=0, column=0, sticky=tk.NSEW)
scrollbar = tk.Scrollbar(main_frame, command=self._canvas.yview)
scrollbar.grid(row=0, column=1, sticky=tk.N+tk.S+tk.W)
self._canvas.configure(yscrollcommand=scrollbar.set)
#self._canvas.bind('<Configure>', lambda *_: self.on_configure())
super().__init__(self._canvas, *args, **kwargs)
self._canvas.create_window((0, 0), window=self, anchor=tk.NW)
# bind <Configure> event on itself
self.bind('<Configure>', lambda _: self.on_configure())