I’ve been working with python for a while now and am just starting to learn wxPython. After creating a few little programs, I’m having difficulty understanding how to create objects that can be shared between dialogs.
Here’s some code as an example (apologies for the length – I’ve tried to trim):
import wx class ExampleFrame(wx.Frame): '''The main GUI''' def __init__(self, parent, id, title): wx.Frame.__init__(self, parent, id, title, size=(200,75)) mainSizer = wx.BoxSizer(wx.VERTICAL) # Setup buttons buttonSizer = wx.BoxSizer(wx.HORIZONTAL) playerButton = wx.Button(self, wx.ID_ANY, 'Player number', wx.DefaultPosition, wx.DefaultSize, 0) buttonSizer.Add(playerButton, 1, wx.ALL | wx.EXPAND, 0) nameButton = wx.Button(self, wx.ID_ANY, 'Player name', wx.DefaultPosition, wx.DefaultSize, 0) buttonSizer.Add(nameButton, 1, wx.ALL | wx.EXPAND, 0) # Complete layout and add statusbar mainSizer.Add(buttonSizer, 1, wx.EXPAND, 5) self.SetSizer(mainSizer) self.Layout() # Deal with the events playerButton.Bind(wx.EVT_BUTTON, self.playerButtonEvent) nameButton.Bind(wx.EVT_BUTTON, self.nameButtonEvent) self.Show(True) return def playerButtonEvent(self, event): '''Displays the number of game players''' playerDialog = PlayerDialogWindow(None, -1, 'Player') playerDialogResult = playerDialog.ShowModal() playerDialog.Destroy() return def nameButtonEvent(self, event): '''Displays the names of game players''' nameDialog = NameDialogWindow(None, -1, 'Name') nameDialogResult = nameDialog.ShowModal() nameDialog.Destroy() return class PlayerDialogWindow(wx.Dialog): '''Displays the player number''' def __init__(self, parent, id, title): wx.Dialog.__init__(self, parent, id, title, size=(200,120)) # Setup layout items self.SetAutoLayout(True) mainSizer = wx.BoxSizer(wx.VERTICAL) dialogPanel = wx.Panel(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL) dialogSizer = wx.BoxSizer(wx.VERTICAL) # Display player number playerNumber = 'Player number is %i' % gamePlayer.number newLabel = wx.StaticText(dialogPanel, wx.ID_ANY, playerNumber, wx.DefaultPosition, wx.DefaultSize, 0) dialogSizer.Add(newLabel, 0, wx.ALL | wx.EXPAND, 5) # Setup buttons buttonSizer = wx.StdDialogButtonSizer() okButton = wx.Button(dialogPanel, wx.ID_OK) buttonSizer.AddButton(okButton) buttonSizer.Realize() dialogSizer.Add(buttonSizer, 1, wx.EXPAND, 5) # Complete layout dialogPanel.SetSizer(dialogSizer) dialogPanel.Layout() dialogSizer.Fit(dialogPanel) mainSizer.Add(dialogPanel, 1, wx.ALL | wx.EXPAND, 5) self.SetSizer(mainSizer) self.Layout() # Deal with the button events okButton.Bind(wx.EVT_BUTTON, self.okClick) return def okClick(self, event): '''Deals with the user clicking the ok button''' self.EndModal(wx.ID_OK) return class NameDialogWindow(wx.Dialog): '''Displays the player name''' def __init__(self, parent, id, title): wx.Dialog.__init__(self, parent, id, title, size=(200,120)) # Setup layout items self.SetAutoLayout(True) mainSizer = wx.BoxSizer(wx.VERTICAL) dialogPanel = wx.Panel(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL) dialogSizer = wx.BoxSizer(wx.VERTICAL) # Display player number playerNumber = 'Player name is %s' % gamePlayer.name newLabel = wx.StaticText(dialogPanel, wx.ID_ANY, playerNumber, wx.DefaultPosition, wx.DefaultSize, 0) dialogSizer.Add(newLabel, 0, wx.ALL | wx.EXPAND, 5) # Setup buttons buttonSizer = wx.StdDialogButtonSizer() okButton = wx.Button(dialogPanel, wx.ID_OK) buttonSizer.AddButton(okButton) buttonSizer.Realize() dialogSizer.Add(buttonSizer, 1, wx.EXPAND, 5) # Complete layout dialogPanel.SetSizer(dialogSizer) dialogPanel.Layout() dialogSizer.Fit(dialogPanel) mainSizer.Add(dialogPanel, 1, wx.ALL | wx.EXPAND, 5) self.SetSizer(mainSizer) self.Layout() # Deal with the button events okButton.Bind(wx.EVT_BUTTON, self.okClick) return def okClick(self, event): '''Deals with the user clicking the ok button''' self.EndModal(wx.ID_OK) return class Player(object): '''A game player''' def __init__(self, number, name): self.number = number self.name = name return def main(): # Start GUI global gamePlayer gamePlayer = Player(1, 'John Smith') app = wx.App(redirect=False) frame = ExampleFrame(None, -1, 'Example frame') frame.Show(True) app.MainLoop() return 0 if __name__ == '__main__': main()
So, I want both of the dialogs to access the gamePlayer object. At the moment, the only way I can think of doing it is to create the gamePlayer object as a global object, but these are normally frowned upon – is there a better way to do this?
There is a method of passing objects in event bindings in this question, but it doesn’t feel quite right.
Is learning to implement the MVC pattern the way forward here?
Thanks.
You can pass a gamePlayer object to
__init__as another argument.In the long run, this isn’t ideal.
You should separate building an empty panel from loading that panel with data. The empty panel is one thing, populating it with data from the model is unrelated.
Populating a frame with data is where you must be given the gamePlayer object which will be used to update the various display widgets.
I’d suggest you look at the Document-View framework for guidance on this. http://docs.wxwidgets.org/stable/wx_docviewoverview.html#docviewoverview. Unfortunately, there aren’t any good Python examples of this, so it can be confusing to convert from the C++ code to Python.
Ultimately, you have a ‘document’ which is the main object (‘gamePlayer’) that is being displayed. Each Frame is a view of that document.