Tkinter 退出时不更新

Posted

技术标签:

【中文标题】Tkinter 退出时不更新【英文标题】:Tkinter does not update while withdrawn 【发布时间】:2018-07-09 15:21:56 【问题描述】:

我有一个程序,当我按下键盘上的热键时,它会在屏幕上显示图像。根据按下的键,将显示不同的图像。 在没有输入 3 秒后,我的根 Tk 得到 withdraw()n 所以屏幕上什么都没有。

现在,每当我想显示图像时,我都会调用此函数:

    def drawOverlay(self, index):
        self.canvas.itemconfig(self.overlayWidget, image=self.overlayImages[index])
        self.deiconify()

问题是我看到旧图像几毫秒后才被替换。

我试图找出为什么会有延迟,尽管我 deiconify() 只是在我切换图像并遇到 this answer 建议使用根的 after() 调用 deiconify() 之后。我试过了,当它仍然不起作用时,我玩了一下这个电话,发现那个电话

self.after(1000, self.deiconify())

使旧图像恰好出现 1 秒钟,然后被新图像替换。

这让我相信TkCanvaswithdraw()n 时无法更新。有没有办法解决?我宁愿在图像显示之前有一个短暂的延迟,而不是旧图像在屏幕上闪烁几帧,但我不知道如何做到这一点。

编辑:所以我是个白痴,因为括号而实际上调用deiconify 而不是将其传递给after。 这确实可以修复在此期间出现的旧图像,但不能修复闪烁。

Edit2:我设法用下面的代码重现了这个问题。

按键盘上的任意键都会出现一个绿色矩形。等待它消失然后按另一个键将出现一个红色矩形。

只有有时您才能看到闪烁的情况,因此请多试几次。当-transparentcolor 未设置时,我无法重现,但我不知道这是由于选项是问题还是由于减少的渲染时间使问题几乎无法察觉。设置overrideredirect 后也更容易看到。

Edit3:我通过使用实际图像进一步简化了代码。即使没有按键或其他事件回调,此代码也会在显示图像之前产生黑色闪光。 -transparentcoloroverrideredirect(True) 似乎对于重现这一点至关重要。在此之前手动调用update() 会降低这种情况发生的频率,但仍会导致在较大图像上持续闪烁。这表明渲染时间是因素之一。

overlay.png

overlayRaw.png

from tkinter import Tk, Canvas
from PIL import ImageTk, Image

TRANSCOLOR = "blue"
IMAGE_SMALL = "overlay.png"
IMAGE_LARGE = "overlayRaw.png"

class Overlay(Tk):
    def __init__(self):
        Tk.__init__(self)

        self.rawImage = Image.open(IMAGE_SMALL)
        self.image = ImageTk.PhotoImage(self.rawImage)
        self.canvas = Canvas(self, width = self.rawImage.size[0], height = self.rawImage.size[1])
        self.canvas.pack()

        self.wm_attributes('-transparentcolor', TRANSCOLOR) # If disabled stops the flashes from ocurring even on large images. 
        self.overrideredirect(True)     # If disabled the Windows animation for opening windows plays. Stops the flashing from ocurring

        self.withdraw()

        self.overlayWidget = self.canvas.create_image(0, 0, image = self.image, anchor = "nw")

        self.deiconify()              # Flashes Clearly Everytime

##        self.update_idletasks()
##        self.deiconify()              # Only Flashes Sometimes. Always flashes on large images

##        self.update()
##        self.deiconify()              # Only Flashes Sometimes. Always flashes on large images

##        self.after(0, self.deiconify) # Flashes Clearly everytime

##        self.after(200, self.deiconify) # Only Flashes Sometimes. Always flashes on large images

##        self.update()
##        self.after(200, self.deiconify) # Flashes Clearly Everytime

o = Overlay()
o.mainloop()

【问题讨论】:

self.after(1000, self.deiconify()) 不会做你认为的那样。它立即调用deiconify,然后休眠一秒钟。 请提供minimal reproducible example,并让我们知道您在哪个平台上运行。 @BryanOakley 我刚刚注意到自己。不幸的是,这并不能解决整个问题。我为我的 Tk 类添加了源代码。我正在使用 Windows 8.1 请不要提供所有代码。创建一个minimal reproducible example。您发布的内容有太多不相关的代码。 请阅读minimal reproducible example 是什么。您的代码不完整,也不是最低限度的。例如,resizable 真的是问题的一部分吗? 【参考方案1】:

我没有看到太多可能导致闪烁的内容。我的建议是在调用deiconify 之前添加对self.update 的显式调用。这应该指示 tkinter 重绘画布上的所有内容。但是,如果您平台上的 tkinter 将绘制推迟到窗口被映射,这将无济于事。

尝试替换这个:

self.after(0,self.deiconify)
self.after(2000, self.hideOverlay)

用这个:

self.update()
self.deiconify()

【讨论】:

我添加了一个更可靠的例子。如果您无法使用较大的图像重现此问题,那么 Windows 8.1 似乎是问题所在,因为我的笔记本电脑获得了与我的 PC 相同的结果

以上是关于Tkinter 退出时不更新的主要内容,如果未能解决你的问题,请参考以下文章

在 Linux 上使用多处理时不出现 TKinter 窗口

Python tkinter 代码在函数内部时不运行

拦截 Tkinter“退出”命令?

tkinter "x" 在退出时执行 ser.close()

tkinter 退出时关闭串行连接

Tkinter python 退出/退出崩溃