我有一个wx.Dialog子类,当用户单击OK按钮时需要执行几个清理操作。 wx.Dialog documentation表示单击“确定”或“取消”应发出EVT_CLOSE事件:
EVT_CLOSE:用户或以编程方式关闭对话框(请参阅Window.Close)。用户可以单击关闭按钮(通常是标题栏右上角的“X”)生成此事件(如果它存在(请参阅CLOSE_BOX样式)或单击带有ID_CANCEL或ID_OK ID的按钮。
然而,我正在使用WX 2.9.5.0(通过wxPython),当我在此测试应用程序中单击“确定”或“取消”时,不会调用OnClose方法。单击系统的关闭按钮(我正在使用OS X)时调用OnClose。我是否实现了此事件处理错误或者wx.Dialog是否真的不符合其文档?在后一种情况下,拦截单击“确定”按钮的最佳方法是什么?
from __future__ import print_function
import wx
class TestDialog(wx.Dialog):
def __init__(self, parent):
wx.Dialog.__init__(self, parent, title='Test Dialog')
sizer = wx.BoxSizer(wx.VERTICAL)
message = wx.StaticText(self, wx.NewId(), 'This is some dummy text')
sizer.Add(message)
ok_button = wx.Button(self, wx.ID_OK, 'OK')
cancel_button = wx.Button(self, wx.ID_CANCEL, 'Cancel')
btn_sizer = self.CreateStdDialogButtonSizer(wx.OK | wx.CANCEL)
btn_sizer.Add(cancel_button)
btn_sizer.Add(ok_button)
sizer.Add(btn_sizer)
self.SetSizer(sizer)
self.Bind(wx.EVT_CLOSE, self.OnClose)
def OnClose(self, event):
print('In OnClose')
event.Skip()
if __name__ == '__main__':
app = wx.App(False)
dialog = TestDialog(None)
result = dialog.ShowModal()
print('Result: {}'.format(result))
答案 0 :(得分:4)
单击模式对话框上的“确定”或“取消”按钮时,对话框未使用Close
关闭,而是以EndModal
结束,因此不会发送EVT_CLOSE
事件。正常完成模态对话框时需要运行的代码通常在调用ShowModal
之后放置。在这种情况下,我认为文档不正确。
OTOH,如果对话框显示为无模式(使用Show
而非ShowModal
),则应使用Close
关闭它们,您将获得EVT_CLOSE
事件。< / p>
答案 1 :(得分:1)
这是因为将调用Destroy()而不是Close()。没有Close(),EVT_CLOSE不会被引发。您可以尝试以下代码。
import wx
class TestDialog(wx.Dialog):
def __init__(self, parent):
wx.Dialog.__init__(self, parent, title='Test Dialog')
sizer = wx.BoxSizer(wx.VERTICAL)
message = wx.StaticText(self, wx.NewId(), 'This is some dummy text')
sizer.Add(message)
ok_button = wx.Button(self, wx.ID_OK, 'OK')
cancel_button = wx.Button(self, wx.ID_CANCEL, 'Cancel')
btn_sizer = self.CreateStdDialogButtonSizer(wx.OK | wx.CANCEL)
btn_sizer.Add(cancel_button)
btn_sizer.Add(ok_button)
sizer.Add(btn_sizer)
self.SetSizer(sizer)
self.Bind(wx.EVT_CLOSE, self.OnClose)
self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy)
def OnClose(self, event):
print 'In OnClose'
event.Skip()
def OnDestroy(self, event):
print 'In OnDestroy'
event.Skip()
if __name__ == '__main__':
app = wx.App(False)
frame = wx.Frame(None)
frame.Show()
dialog = TestDialog(frame)
result = dialog.ShowModal()
dialog.Close(True)
print 'Result: {}'.format(result)
app.MainLoop()
答案 2 :(得分:0)
对于任何寻找类似问题答案的人...你可以捕获OK按钮点击事件,只在你想要关闭表单时调用event.Skip()。如果你不打电话,就不会打电话给Destroy()。我不知道如何在wxPython中编写它,但在C ++中它将是:
//
答案 3 :(得分:0)
我只是遇到了这个问题,并根据答案here,提出了以下解决方案。已使用wxPython 4.1.0和python 3.8.5进行了测试。
实质上,wx.EVT_BUTTON
窗口中的所有wx.Dialog
事件都绑定到wx.Dialog
窗口中的方法。在该方法中,将单击的按钮的ID与wx.Dialog
中用于创建按钮的ID进行比较,并据此采取措施。
在下面的示例中,单击“确定”按钮将生成一个随机数。 wx.Dialog
仅在随机数> 0.5时关闭。
import random
import wx
class Example(wx.Frame):
"""Main window """
#region ---> Instance Setup
def __init__(self, parent):
#region ---> Initial setup
super().__init__(
parent,
title = 'Intercept wx.Dialog button events',
size = (260, 180),
)
#endregion ---> Initial setup
#region ---> Widgets
self.btn = wx.Button(self, label = 'Show Dialog Window')
#endregion ---> Widgets
#region ---> Sizers
self.Sizer = wx.BoxSizer()
self.Sizer.Add(self.btn, 0, wx.ALIGN_CENTER|wx.ALL, 5)
self.SetSizer(self.Sizer)
#endregion ---> Sizers
#region ---> Bind
self.btn.Bind(wx.EVT_BUTTON, self.OnDialog)
#endregion ---> Bind
#region ---> Show
self.Centre()
self.Show()
#endregion ---> Show
#---
#endregion ---> Instance Setup
#region ---> Class methods
def OnDialog(self, event):
""""""
with MyDialog(self) as dlg:
if dlg.ShowModal() == wx.ID_OK:
print("Dialog closed with OK - Message from Main Window")
print("")
else:
print("Dialog closed with Cancel - Message from Main Window")
print("")
#---
#endregion ---> Class methods
#---
class MyDialog(wx.Dialog):
""""""
#region ---> Instance Setup
def __init__(self, parent):
#region ---> Initial setup
super().__init__(
parent,
title = 'My Dialog',
size = (220, 90),
)
#endregion ---> Initial setup
#region ---> Sizer
self.btnSizer = self.CreateStdDialogButtonSizer(
wx.OK|wx.CANCEL
)
self.Sizer = wx.BoxSizer()
self.Sizer.Add(self.btnSizer, 0, wx.ALIGN_CENTER|wx.ALL, 5)
self.SetSizer(self.Sizer)
#endregion ---> Sizer
#region ---> Show
self.CentreOnParent()
#endregion ---> Show
#region ---> Bind
self.Bind(wx.EVT_BUTTON, self.OnButton) # HERE IS THE TRICK, Get all Button events
#endregion ---> Bind
#---
#endregion ---> Instance Setup
#region ---> Class methods
def OnButton(self, event):
"""Process the OK button click"""
#region ---> Get the id of the clicked button
clicked_button_id = event.GetEventObject().GetId()
#endregion ---> Get the id of the clicked button
#region ---> Identify the clicked button & act accordingly
if clicked_button_id == wx.ID_OK:
print("Processing OK button click")
if (n := random.random()) > 0.5:
#--> Everything fine, window will close
print(n, "> 0.5. Ok, closing window")
pass
else:
#--> Error, window will remain open
print(n, "< 0.5. Not Ok, window remains open")
return False
else:
print("Processing Cancel button click")
#endregion ---> Identify the clicked button & act accordingly
#region ---> Skip event to make sure default behavior is executed
event.Skip()
#endregion ---> Skip event to make sure default behavior is executed
#---
#endregion ---> Class methods
#---
if __name__ == '__main__':
app = wx.App()
Example(None)
app.MainLoop()