I'm struggling to find a way to use function from within a wxPython event handler function. Say I have a button that when clicked it runs a function called OnRun using an event handler. However, the user forgot to click a RadionButton before the OnRun button and I want to pop-up a MessageDialog telling them they forgot a step. I'm going to reuse this MessageDialog several times, thus rather than doing a copy/paste of the same code I would like to just have this MessageDialog in a function and call this MessageDialog function if the user forgets to check a RadioButton.
If this wasn't a function used in an Event Handler I know I could simply put the function as an argument but I'm not seeing a way I can do this with these. Any help here would be appreciated.
The following code shows how to create a little method that you can reuse to show custom dialogs and tells the user that they need to accept the agreement. You can change the conditionals to do whatever you want, of course. And you can change the "showMsg" method so that the icon changes too with just a little tweaking.
import wx
########################################################################
class TestFrame(wx.Frame):
""""""
#----------------------------------------------------------------------
def __init__(self):
"""Constructor"""
wx.Frame.__init__(self, None, title="Test")
panel = wx.Panel(self)
self.radios = wx.RadioBox(panel, label="Choices",
choices = ["None", "Accept", "Reject"])
button = wx.Button(panel, label="Run")
button.Bind(wx.EVT_BUTTON, self.onBtn)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.radios, 0, wx.ALL, 5)
sizer.Add(button, 0, wx.ALL, 5)
panel.SetSizer(sizer)
#----------------------------------------------------------------------
def onBtn(self, event):
""""""
btn = event.GetEventObject()
btn.SetLabel("Running")
radio_value = self.radios.GetStringSelection()
if radio_value == "None":
self.showMsg("Error", "Please Choose 'Accept' or 'Reject'!")
elif radio_value == "Accept":
self.showMsg("Message", "Thank you for accepting!")
else:
self.showMsg("Message", "We're sorry, but you cannot continue the install")
#----------------------------------------------------------------------
def showMsg(self, title, msg):
""""""
dlg = wx.MessageDialog(None, msg, title, wx.OK | wx.ICON_QUESTION)
dlg.ShowModal()
dlg.Destroy()
if __name__ == "__main__":
app = wx.App(False)
frame = TestFrame()
frame.Show()
app.MainLoop()
I will make a stab at this, even if the answer seems too direct. I would set a property in the enclosing frame that flags whether the Radio Button has been clicked or not. Then when OnRun
is called check that property. Should it be in the wrong state, call the MessageDialog and abort/pause/modify the OnRun
.
EDIT Here is what I mean, a trivial example with two buttons, neither of which will lead to further action unless a user agreement is clicked.
import wx
class ButtonFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1, 'Button Example',
size=(300, 100))
panel = wx.Panel(self, -1)
self.radio = wx.RadioButton(panel, -1, "Accept user agreement", pos=(50, 10))
self.button = wx.Button(panel, -1, "Run", pos=(50, 30))
self.Bind(wx.EVT_BUTTON, self.OnRun, self.button)
self.button.SetDefault()
self.btn2 = wx.Button(panel, -1, "Walk", pos=(150, 30))
self.Bind(wx.EVT_BUTTON, self.OnWalk, self.btn2)
def OnRun(self, event):
if not self.CheckRadio():
return
self.button.SetLabel("Running")
def OnWalk(self, event):
if not self.CheckRadio():
return
self.btn2.SetLabel("Walking")
def CheckRadio(self):
accepted = self.radio.GetValue()
if not accepted:
dlg = wx.MessageDialog(None, 'First accept the user agreement',
'MessageDialog', wx.OK | wx.ICON_QUESTION)
result = dlg.ShowModal() # result not used in this demo
dlg.Destroy()
return False
else:
return True
if __name__ == '__main__':
app = wx.PySimpleApp()
frame = ButtonFrame()
frame.Show()
app.MainLoop()
Code is adapted from Listing 7.11 of wxPython in Action. I hope this helps, if you have not already solved this n the time that has passed.
You can create your own MessageDialog (inheriting), or you can use functools.partial/lambda to pass an additional argument to the event handler:
self.Bind(wx.MY_EVENT, lambda evt: self.OnEventX(evt, handler=foo), id=12)