Tkinter w.destroy() 阻止/重置窗口调整大小 [英] Tkinter w.destroy() blocks/resets window resize

查看:28
本文介绍了Tkinter w.destroy() 阻止/重置窗口调整大小的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个使用 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆