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
相关产品推荐
相关产品推荐

