解决wxpython调用self.Destroy()却无法关闭窗口的情况

6 篇文章 0 订阅

问题背景:

今天遇到了一个奇特的问题,使用wx设计gui界面,调用self.Destroy()关闭窗口,却在某些时候无法立刻关闭。

总结规律发现,窗口激活的时候发起self.Destroy(),窗口可以正常关闭;窗口未激活的时候发起self.Destroy(),窗口就不会关闭,但是鼠标路过的时候就会立刻关闭。

找到原因:

奇葩问题检查了好久,终于找到原因,原理其实很简单:

对于gui库,无论是tkinter,还是wxpython,或者pyqt,单线程的Python都是通过事件循环响应窗口操作。移动窗口是事件、拉伸窗口是事件、点击按钮是事件。有事件的时候窗口就根据需要更新,没有事件的时候窗口就不变。

而我外部发起的self.Destroy(),并不是窗口事件,所以窗口不会更新,界面不会销毁。而鼠标路过的时候触发了鼠标进入事件,窗口更新,就把自己给关闭了。

另外窗口处于激活状态时,点击任务栏图标,会首先产生窗口失去焦点事件,窗口也会刷新,也能把自己关闭。

测试例子:

运行后显示窗口,并会在系统托盘显示图标。鼠标左键单击和右键单击测试调用两种方法尝试关闭窗口(点击后需重启程序)。

鼠标左键调用self.Destroy()方法关闭窗口,当窗口处于激活状态时可以关闭窗口,当窗口处于非激活状态时窗口不会关闭,但是鼠标路过(触发鼠标进入事件)时就会关闭。

鼠标右键调用wx.CallAfter(self.Destroy)关闭窗口,使用发起新事件的方法关闭窗口,事件处理完毕后退出MainLoop事件循环,窗口销毁。

但是如果在self.Destroy()销毁窗口前,调用self.SetFocus()激活窗口,也可以将窗口关闭,但是有些绕弯路,可根需要据情况使用。

示例代码:

import wx
import wx.adv


class MyTaskBarIcon(wx.adv.TaskBarIcon):
    def __init__(self, parent):
        wx.adv.TaskBarIcon.__init__(self, wx.adv.TBI_DOCK) # wx.adv.TBI_CUSTOM_STATUSITEM
        self.icon = wx.Icon(wx.Bitmap(wx.Image(IMG_ICON)))
        self.SetIcon(self.icon)

        self.Bind(wx.adv.EVT_TASKBAR_LEFT_UP, parent.OnClose1)
        self.Bind(wx.adv.EVT_TASKBAR_RIGHT_UP, parent.OnClose2)


class MyFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, -1, style=wx.STAY_ON_TOP) # | wx.BORDER_NONE
        self.icon = MyTaskBarIcon(self)
        self.Center()
        self.Show()

    def OnClose1(self, evt):
        print('OnClose1')
        self.icon.Destroy() # only `RemoveIcon` will still run in mainloop.
        print('icon.Destroy')
        # self.SetFocus()
        self.Destroy()
        print('Destroy')

    def OnClose2(self, evt):
        print('OnClose2')
        self.icon.Destroy() # only `RemoveIcon` will still run in mainloop.
        print('icon.Destroy')
        wx.CallAfter(self.Destroy)
        print('CallAfter Destroy')


if __name__ == '__main__':
    IMG_ICON = 'icon.ico'
    app = wx.App()
    frm = MyFrame()
    app.MainLoop()
    print('end')
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值