wx.Dialog中的ESC键不会触发ID_CANCEL按钮,除非该按钮获得焦点

0 投票
1 回答
756 浏览
提问于 2025-04-18 17:46

根据文档,在wxPython中创建的对话框,如果用ShowModal显示,应该能处理ESC键。它的做法是找一个ID为ID_CANCEL的按钮,然后模拟点击这个按钮,也就是触发它的EVT_BUTTON事件。

这个功能在我所有的对话框中都能正常工作,除了一个。经过大量的调试,我发现取消按钮,或者说任何一个按钮,都需要获得焦点。换句话说,只要我在我创建的按钮上调用.SetFocus(),那么ESC键就能正常工作了。

有没有人知道这是怎么回事?用ShowModal()显示的对话框是不是不会自动获得焦点?应该获得吗?还是我理解错了什么?

在下面的示例代码中,取消注释b.SetFocus()那一行,就能看到区别:

import wx
class MainWindow(wx.Frame):
    def __init__(self, parent):
        super(MainWindow, self).__init__(parent)
        self.Show()
        d = SomeDialog(self)
        d.ShowModal()
        self.Destroy()
class SomeDialog(wx.Dialog):
    def __init__(self, parent):
        super(SomeDialog, self).__init__(parent)
        button = wx.Button(self, wx.ID_CANCEL, 'Cancel')
        button.Bind(wx.EVT_BUTTON, self.action_cancel)
        #button.SetFocus()
    def action_cancel(self, e):
        self.EndModal(wx.ID_CANCEL)
if __name__ == '__main__':
    app = wx.App(False)
    frame = MainWindow(None)
    app.MainLoop()

更新:这个问题在linux(Fedora 20,Gnome)上出现。

1 个回答

2

你可以调用对话框的 SetFocus() 方法来让它自己获得焦点:

import wx

class MainWindow(wx.Frame):

    def __init__(self, parent):
        super(MainWindow, self).__init__(parent)
        self.Show()
        d = SomeDialog(self)
        d.ShowModal()
        self.Destroy()

class SomeDialog(wx.Dialog):

    def __init__(self, parent):
        super(SomeDialog, self).__init__(parent)
        button = wx.Button(self, wx.ID_CANCEL, 'Cancel')
        button.Bind(wx.EVT_BUTTON, self.action_cancel)
        self.SetFocus()

    def action_cancel(self, e):
        self.EndModal(wx.ID_CANCEL)

if __name__ == '__main__':
    app = wx.App(False)
    frame = MainWindow(None)
    app.MainLoop()

这个方法在 Kubuntu 14.04 系统上,使用 wxPython 2.8.12.1 和 Python 2.7.6 时是有效的。不过,我怀疑当你把焦点设置到对话框时,它可能会把焦点传递给它的第一个子控件,就像 wx.Panel 一样。我不太明白为什么 Linux 会这样表现,但我同意 @nepix32 和 @VZ 的看法,这个功能应该在不使用 SetFocus() 的情况下也能正常工作。你可以把它当作一种解决方法来调用,但你可能应该把这个问题报告为一个bug。在 wxPython 网站上有一个链接,你可以在那提交你的bug报告。

撰写回答