我正在开发 tkinter 中的应用程序。无法发布代码,因为它太复杂并且在简化版本中看不到工件。
您可以在附加的视频中看到,如果我调整整个窗口的大小,它看起来还不错。它不是完美的光滑,但没关系。但是,当我使用 PanedWindos 窗扇调整大小时,在调整大小期间会看到很多伪影。最后,当我释放鼠标按钮时,它看起来还不错。
你有这方面的经验吗?一些提示什么可能导致这种行为?
调整大小的 youtube 视频
编辑:
我创建了重现该行为的最小版本。ScrollFrame 类使工件更加明显。
import tkinter as tk
import random
class ScrollFrame(tk.Frame):
def __init__(self, parent, **kwargs):
super().__init__(parent, **kwargs)
self.canvas = tk.Canvas(self, borderwidth=0, highlightthickness=0)
self.canvas.bind("<Enter>", self._bind_mouse)
self.canvas.bind("<Leave>", self._unbind_mouse)
self.viewPort = tk.Frame(self.canvas)
self.vsb = tk.Scrollbar(self, orient="vertical", command=self.canvas.yview)
self.canvas.configure(yscrollcommand=self.vsb.set)
self.vsb.pack(side="right", fill="y")
self.canvas.pack(side="left", fill="both", expand=True)
self.canvas_window = self.canvas.create_window((4, 4), window=self.viewPort,
anchor="nw",
tags="self.viewPort",
)
self.viewPort.bind("<Configure>", self.onFrameConfigure)
self.canvas.bind("<Configure>", self.onCanvasConfigure)
self.onFrameConfigure(None)
def onFrameConfigure(self, event):
'''Reset the scroll region to encompass the inner frame'''
self.canvas.configure(scrollregion=self.canvas.bbox(
"all"))
def onCanvasConfigure(self, event):
'''Reset the canvas window to encompass inner frame when required'''
canvas_width = event.width
self.canvas.itemconfig(self.canvas_window,
width=canvas_width)
def _bind_mouse(self, event=None):
self.canvas.bind_all("<4>", self._on_mousewheel)
self.canvas.bind_all("<5>", self._on_mousewheel)
self.canvas.bind_all("<MouseWheel>", self._on_mousewheel)
def _unbind_mouse(self, event=None):
self.canvas.unbind_all("<4>")
self.canvas.unbind_all("<5>")
self.canvas.unbind_all("<MouseWheel>")
def _on_mousewheel(self, event):
"""Linux uses event.num; Windows / Mac uses event.delta"""
if self.vsb.get() != (0, 1):
if event.num == 4 or event.delta > 0:
self.canvas.yview_scroll(-1, "units")
elif event.num == 5 or event.delta < 0:
self.canvas.yview_scroll(1, "units")
class OptionAttribute:
def __init__(self, target_widget, name, options, unit):
self.name = tk.Label(target_widget, text=name)
self.input = tk.Button(target_widget, text=options[0], anchor='w',
command=lambda: self.show_options(self.input), relief='flat', bg='white', bd=0)
self.menu = tk.Menu(target_widget, tearoff=0)
for o in options:
self.menu.add_command(label=o, command=lambda selected=o: self.input.configure(text=selected))
self.unit = tk.Label(target_widget, text=unit)
def show_options(self, widget):
self.input.focus_set()
self.menu.post(widget.winfo_rootx(), widget.winfo_rooty())
if __name__ == '__main__':
root = tk.Tk()
root.minsize(width=640, height=480)
root.grid_columnconfigure(0, weight=1)
root.grid_rowconfigure(0, weight=1)
pw = tk.PanedWindow(root, orient='horizontal', sashrelief='ridge', sashwidth=8)
f1 = tk.Frame(pw)
pw.add(f1, stretch='always', minsize=200, width=400)
f2 = tk.Frame(pw)
f2.grid_columnconfigure(0, weight=1)
f2.grid_rowconfigure(0, weight=1)
f2_scroll = ScrollFrame(f2)
f2_scorr_inner = f2_scroll.viewPort
f2_scorr_inner.grid_columnconfigure(1, weight=80)
f2_scorr_inner.grid_columnconfigure(2, weight=20)
f2_scroll.grid(sticky='nsew')
option_attrs = [OptionAttribute(f2_scorr_inner,
str(random.randint(0, 100000)),
[str(random.randint(0, 100000)) for __ in range(10)],
random.choice(['mm', 'nm', 'kg', 'h', 'km', ])
) for _ in range(100)]
r = 0
for oa in option_attrs:
oa.name.grid(column=0, row=r, sticky='w', padx=(0, 10))
oa.input.grid(column=1, row=r, sticky='w')
oa.unit.grid(column=2, row=r, sticky='w')
r += 1
tk.Frame(f2_scorr_inner, height=1, bg="gray80").grid(column=0, row=r, sticky="ew", columnspan=3)
r += 1
pw.add(f2, stretch='always', minsize=200, width=400)
pw.grid(sticky='nsew')
root.mainloop()