wxPython 和在窗口之间共享对象

41 阅读2分钟

我想在两个对话框之间共享一个对象。目前,我能想到的唯一方法是将该对象创建为全局对象,但通常不建议这样做。有没有更好的方法来实现这一点?

解决方案

有两种方法可以解决这个问题:

  1. 将对象作为另一个参数传递给 __init__

    def __init__(self, parent, id, title, gamePlayer ):
        ...etc...
    
  2. 使用 MVC(模型-视图-控制器)模式。

    MVC 模式是一种设计模式,可以将应用程序的逻辑分为三个部分:

    • 模型:与应用程序的数据相关。
    • 视图:应用程序的用户界面。
    • 控制器:处理用户输入并更新模型和视图。

    使用 MVC 模式,可以将对象存储在模型中,然后在视图中显示它。控制器负责处理用户输入并更新模型和视图。

MVC 模式是一种很好的方法,可以将应用程序的逻辑与用户界面分离开来。这使得应用程序更容易维护和扩展。

代码示例

方式一:将对象作为另一个参数传递给 __init__

import wx

class ExampleFrame(wx.Frame):
    """The main GUI"""
    def __init__(self, parent, id, title, gamePlayer):
        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", self.gamePlayer)
        playerDialogResult = playerDialog.ShowModal() 
        playerDialog.Destroy()
        return

    def nameButtonEvent(self, event):
        """Displays the names of game players"""
        nameDialog = NameDialogWindow(None, -1, "Name", self.gamePlayer)
        nameDialogResult = nameDialog.ShowModal() 
        nameDialog.Destroy()
        return

class PlayerDialogWindow(wx.Dialog):
    """Displays the player number"""
    def __init__(self, parent, id, title, gamePlayer):
        wx.Dialog.__init__(self, parent, id, title, size=(200,120))
        self.gamePlayer = gamePlayer

        # 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" % self.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, gamePlayer):
        wx.Dialog.__init__(self, parent, id, title, size=(200,120))
        self.gamePlayer = gamePlayer

        # 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" % self.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", gamePlayer)
    frame.Show(True)
    app.MainLoop()
    return 0

if __name__ == '__main__':
    main()

方式二:使用 MVC 模式

import wx

class Model:
    def __init__(self):
        self.gamePlayer = Player(1, "John Smith")

class View(wx.Frame):
    def __init__(self, parent, model):
        wx.Frame.__init__(self, parent, -1, "Example frame")
        self.model = model

        # 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 = wx.BoxSizer(wx.VERTICAL)
        mainSizer.Add(buttonSizer, 1, wx.EXPAND, 5)
        self.SetSizer(mainSizer)
        self.Layout()

        # Deal with the events
        playerButton.Bind(wx.EVT_BUTTON, self.playerButtonEvent)
        nameButton.