2

我已经使用 python 有一段时间了,并且刚刚开始学习 wxPython。在创建了一些小程序之后,我很难理解如何创建可以在对话框之间共享的对象。

以下是一些代码作为示例(为长度道歉 - 我试图修剪):

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()

所以,我希望这两个对话框都能访问 gamePlayer 对象。目前,我能想到的唯一方法是将 gamePlayer 对象创建为全局对象,但这些通常是不受欢迎的——有没有更好的方法来做到这一点?

这个问题中有一种在事件绑定中传递对象的方法,但感觉不太对劲。

学习实现 MVC 模式是前进的方向吗?

谢谢。

4

2 回答 2

3

您可以将 gamePlayer 对象__init__作为另一个参数传递给。

def __init__(self, parent, id, title, gamePlayer ):
    ...etc...

从长远来看,这并不理想。

您应该将构建一个空面板与加载该面板的数据分开。空面板是一回事,用模型中的数据填充它是不相关的。

使用数据填充帧是必须为您提供 gamePlayer 对象的地方,该对象将用于更新各种显示小部件。

我建议您查看 Document-View 框架以获得这方面的指导。 http://docs.wxwidgets.org/stable/wx_docviewoverview.html#docviewoverview。不幸的是,没有任何好的 Python 示例,因此从 C++ 代码转换为 Python 可能会令人困惑。

最终,您有一个“文档”,它是正在显示的主要对象(“gamePlayer”)。每个框架都是该文档的一个视图。

于 2008-12-24T19:42:02.257 回答
1

模型-视图-控制器 (MVC) 框架允许您访问公共数据 (模型) 并通过控制器将其显示在您的 GUI (视图) 中。在这里可以找到一个很好的解释:

wxPython 的 MVC 框架

基本上,您可以通过不允许模型直接与视图对话,而是将其发布到已进行更改的控制器来避免混乱。然后控制器适当地更新视图。同样用于从您的 gui 上的控件更新模型。这样,模型和视图代码是独立的,它们与访问每个 API 的控制器代码绑定在一起。

于 2013-12-02T17:42:28.160 回答