You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

wxPython中从Dialog调用MessageBox后如何将焦点切回Dialog

问题描述

我在使用wxPython时想要实现如下效果:

  • 创建一个Frame窗口
  • 从该Frame中调用一个Dialog对话框
  • 从该Dialog中调用MessageBox提示框
  • 点击MessageBox上的"ok"按钮关闭弹窗
  • 关闭后焦点应当回到Dialog上

但实际运行后Dialog虽然仍在前台,焦点却落在了Frame上!

我使用的软件版本如下:

  • wxPython: 4.1.0 gtk3 (phoenix) wxWidgets 3.1.4
  • Python: 3.8.10
  • 操作系统: 5.4.0-90-generic #101-Ubuntu

以下是我编写的示例程序:

import wx


class Dialog1(wx.Dialog):

    def __init__(self, parent):
        wx.Dialog.__init__(self, id=wx.ID_ANY, name='', parent=parent,
              pos=wx.Point(500, 100), size=wx.Size(500, 200),
              style=wx.DEFAULT_DIALOG_STYLE, title='My Dialog')
                
        box = wx.BoxSizer(wx.VERTICAL)

        button1 = wx.Button(self, wx.ID_ANY, "open MessageBox")
        button1.Bind(wx.EVT_BUTTON, self.DisplayMessage)
        box.Add(button1, 0, wx.ALL, 10)
        
        self.orderNr = wx.TextCtrl(self, id=wx.ID_ANY, style=0, value='')
        box.Add(self.orderNr, 0, wx.ALL, 10)

        self.SetSizer(box)
        self.Layout()
        
        
    def DisplayMessage(self, event):
        #wx.MessageBox('Important Message')
        wx.MessageBox('Important Message', parent=self)
        self.orderNr.SetFocus()
        #event.Skip()
        
        
class Frame(wx.Frame):

    def __init__(self, title):
        wx.Frame.__init__(self, None, title=title, pos=(150, 150), size=(350, 200))

        panel = wx.Panel(self)
        box = wx.BoxSizer(wx.VERTICAL)

        m_text = wx.StaticText(panel, -1, "Hello World!")
        box.Add(m_text, 0, wx.ALL, 10)

        button1 = wx.Button(panel, wx.ID_ANY, "open Dialog")
        button1.Bind(wx.EVT_BUTTON, self.OpenDialog)
        box.Add(button1, 0, wx.ALL, 10)
        
        panel.SetSizer(box)
        panel.Layout()


    def OpenDialog(self, event):
        dialog1 = Dialog1(self)
        dialog1.ShowModal()
        #event.Skip()


app = wx.App(None)
top = Frame("My Frame")
top.Show()
app.MainLoop()

解决方案

这是GTK3平台下wxPython的已知适配问题,MessageBox关闭后系统默认的焦点事件会优先把焦点切回根Frame,你直接在MessageBox之后调用SetFocus的时机太早,会被后续未处理的系统事件覆盖。
只要把焦点设置的操作延迟到事件队列清空后执行即可,修改DisplayMessage方法:

def DisplayMessage(self, event):
    wx.MessageBox('Important Message', parent=self)
    # 延迟执行焦点设置,避开系统默认焦点事件的影响
    wx.CallAfter(self.orderNr.SetFocus)

如果修改后还是偶发焦点切回Frame的情况,可以再加一步把Dialog置顶的操作,双重保障:

def DisplayMessage(self, event):
    wx.MessageBox('Important Message', parent=self)
    def restore_focus():
        self.Raise()
        self.orderNr.SetFocus()
    wx.CallAfter(restore_focus)

修改后测试,关闭MessageBox后焦点就会稳定落在Dialog的输入框中。


内容的提问来源于stack exchange,提问作者Leon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 05:24:07