Tkinter w.destroy() 阻止/重置窗口调整大小 [英] Tkinter w.destroy() blocks/resets window resize
问题描述
我有一个使用 tkinter 的 Python 3.5 应用程序,并在画布中即时创建/删除小部件.我注意到在窗口调整大小的回调期间使用 w.destroy() 销毁小部件时,回调正确完成,但窗口正在重置为其原始大小.
I have a Python 3.5 app using tkinter and create/remove widgets in a canvas on the fly. I noticed that when a widget is being destroyed using w.destroy() during the callback of a window resize, the callback finished correctly, but the window is being reset to its original size.
我尝试使用 self.after(1000, self.resize) 延迟 w.destroy() 并且这种关闭有效但是在触发回调时向下拖动/按住光标时,调整大小会跳回无论如何.
I've tried to delay the w.destroy() using self.after(1000, self.resize) and that kind off works but when dragging/holding the cursor down while the callback is being fired, the resize jumps back anyway.
有人建议动态删除小部件并释放内存吗?
Anyone having a suggestion to remove widgets on the fly and release memory?
更新:作为一种解决方法,我使用 w.delete=True 标记要删除的小部件,并在after"回调中删除标记为删除的小部件.
UPDATE: As a workaround I mark widgets to be deleted with w.delete=True and in an 'after' callback delete the widgets which are marked for deletion.
这是一个简化的示例来说明问题:
Here is a stripped down sample to illustrate the issue:
更新:将代码简化到最低限度以重现问题.
UPDATE: Simplified code to bare minimum to reproduce issue.
from tkinter import ALL, N, E, W, S, Canvas, Tk, ttk
class Resize(Tk):
def __init__(self):
super().__init__()
self.init = True
self.canvas = None
self.position_window()
self.create_canvas()
def resize(self):
if self.init:
self.init = False
return
# delete(ALL) will remove the widget from the display, but widget
# remains in memory as child of canvas. Resizing works ok.
self.canvas.delete(ALL)
# widget.destroy() will release memory of widget, but blocks/resets resizing.
# Window gets resized by 1-2 pixels and jumps back to its original size.
[child.destroy() for child in self.canvas.winfo_children()]
def create_canvas(self):
self.columnconfigure(0, weight=1)
self.rowconfigure(0, weight=1)
self.canvas = Canvas(self)
self.canvas.grid(row=0, column=0, sticky=(N, S, W, E))
self.canvas.bind('<Configure>', lambda *args: self.resize())
entry = ttk.Label(self.canvas, text='Some dummy text')
self.canvas.create_window(20, 20, window=entry, anchor='w')
def position_window(self):
self.resizable(1, 1)
sceenwidth = self.winfo_screenwidth()
screenheight = self.winfo_screenheight()
self.update_idletasks()
width = 600
height = 300
left = sceenwidth / 2 - width / 2
top = (screenheight / 2 - height / 2) / 3
self.geometry("%dx%d%+d%+d" % (width, height, left, top))
if __name__ == '__main__':
Resize().mainloop()
推荐答案
我没有尝试您的代码,但我在自己的项目中遇到了同样的问题.
I did not try your code, but I had the same problem with my own project.
窗口不仅仅是在 destroy()
上调整大小/重置;
事件似乎被中断了.无论我调整了多少或多少,窗口总是恢复到第一个
回调.正因为如此,或者随之而来的是,Button-1 会自动释放,防止窗口大小调整手柄跟随鼠标.
The window wasn't just resizing/resetting on destroy()
; the <Configure>
event was seemingly interrupted.
The window always reverted back to the very first <Configure>
call back no matter how much or how little I resized. Because of that, or along with that, Button-1 was automatically releasing, preventing the window resize grip from following the mouse.
换句话说,窗口边缘从鼠标下方滑出",就像 Windows 中的滚动条在鼠标移动得太远时会重置中间滚动一样.
In other words, the window edge was "slipping out" from under the mouse, much like a scrollbar in Windows will reset mid-scroll when the mouse moves too far from it.
无论如何,一个解决方案是使用 ttk.Sizegrip 并禁止使用窗口边框调整顶级窗口的大小.
Anyways, a solution is to use ttk.Sizegrip and prohibit resizing the top level window with the window borders.
这篇关于Tkinter w.destroy() 阻止/重置窗口调整大小的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!