如何保持控制器存活

vak0160

我正在尝试使用此链接实现MVC模式一切正常,直到我使用其控制器创建了第二帧。第一帧的控制器仍然有效,因为该代码已被以下内容阻止:

app.MainLoop()

但是当第二个控制器(在按钮事件中创建)时,将被GC化,因为它已经脱离上下文了。我不想将控制器引用到视图,因为我想尝试被动视图方法,即视图很笨,控制器会更新视图,这也会引起循环引用。

这是我调用控制器的方式:

def OnClick(self, evt):
    controller = MyController2()

如果我像这样将控制器引用到父控制器:

def OnClick(self, evt):
    self.controller = MyController2()

控制器仍在运行,但是即使我关闭第二帧,控制器也不会仍在运行吗?如何使第二个控制器保持活动状态,但在关闭其视图后仍可以将其GC化?我也想使视图保持逻辑清晰,因为它已经包含了小部件定义(我在一帧中有很多小部件)。

对于我的英语不好,我们将不胜感激。

编辑:

这是我的控制器获取垃圾的示例。本示例使用眨眼而不是pubsub。

import wx

from blinker import signal

class ChildView(wx.Frame):
    def __init__(self, parent):
        wx.Frame.__init__(self, parent)

        sizer = wx.BoxSizer()

        self.btn_child = wx.Button(self, label="click me")
        sizer.Add(self.btn_child)

        self.SetSizer(sizer)
        self.Center()

        # events
        self.btn_child.Bind(wx.EVT_BUTTON, self.on_btn_child_click)

    def on_btn_child_click(self, event):
        signal("child.btn_child_click").send(self)

class ChildController(object):
    def __init__(self, parent):
        self.view = ChildView(parent)

        self.subscribe_signal()

        self.view.Show()

    def subscribe_signal(self):
        signal("child.btn_child_click").connect(self.on_btn_child_click)

    def on_btn_child_click(self, sender):
        print "button on child clicked"

class ParentView(wx.Frame):
    def __init__(self, parent):
        wx.Frame.__init__(self, parent)

        sizer = wx.BoxSizer()

        self.btn = wx.Button(self, label="show child window")
        sizer.Add(self.btn)

        self.SetSizer(sizer)
        self.Center()

        # events
        self.btn.Bind(wx.EVT_BUTTON, self.on_btn_click)

    def on_btn_click(self, event):
        signal("parent.btn_click").send(self)

class ParentController(object):
    def __init__(self):
        self.view = ParentView(None)

        self.subscribe_signal()

        self.view.Show()

    def subscribe_signal(self):
        signal("parent.btn_click").connect(self.on_btn_click)

    def on_btn_click(self, sender):
        child_controller = ChildController(self.view)

def main():
    app = wx.App()

    controller = ParentController()

    app.MainLoop()

if __name__ == '__main__':
    main()

如您所见,孩子的按钮无法正常工作,因为它的控制器已经被垃圾回收了(没有人引用该控制器)。我已经尝试过一些解决方案,例如:

  1. 在父控制器中引用子控制器。子项关闭后,除非我手动删除它或将其替换为新的控制器(重新打开子项窗口),否则子项控制器将仍然有效。如果控制器保存大量数据,这尤其糟糕。

  2. 控制器和视图之间的循环引用(在controller-> view上具有weakref)。这是我最好的选择,但我想避免循环引用。

因此,我应该在哪里引用孩子的控制器以使其保持生命?

绿玉

好吧,这是一个大话题:如何在wxPython中执行MVC。没有一个正确的答案。选择任何答案,您都会在尝试认真遵循设计模式时遇到困难的选择。

那里的一些示例不够复杂,无法解决其中的一些问题。这是我创建的一个示例,试图说明适用于我的方法。

您可以看到在View元素的创建和控制器之间没有任何耦合,并且控制器拥有“设置应用程序”的逻辑。视图确实是被动的-它的元素仅在需要满足控制器动作时才存在。

我添加了两个视图实现,您可以在使用命令行参数之间进行选择。我要显示的是,这是对您是否已实现良好的控制器/视图分离的真实测试-您应该能够插入其他视图实现,而不必完全更改控制器。控制器取决于业务逻辑(包括应用程序中可能发生的事件的种类)和模型API。它不依赖于视图中的任何内容。

档案:mvc_demo_banking_simulator.py

#!/usr/bin/env python

# This is a demo/example of how you might do MVC (Passive View) in wxpython.
import sys

import wx

from wx.lib.pubsub import setupkwargs
from wx.lib.pubsub import pub

from enum import Enum

import logging

import bank_view
import bank_view_separate_frames


#####
#   The control events that the Controller can process
#   Usually this would be in a module imported by each of M, V and C
#   These are the possible values for the "event" parameter of an APP_EVENT message

class AppEvents(Enum):
    APP_EXIT = 0
    APP_ADD_WORKPLACE = 1
    APP_ADD_CUSTOMER = 2
    CUSTOMER_DEPOSIT = 3
    CUSTOMER_WITHDRAWAL = 4
    CUSTOMER_EARN = 5
    PERSON_WORK = 6
    EARN_REVENUE = 7

#############
#

class Controller:
    def __init__(self, view_separate_frames):
        self._log = logging.getLogger("MVC Logger")
        self._log.info("MVC Main Controller: starting...")

        pub.subscribe(self.OnAppEvent, "APP_EVENT")

        if view_separate_frames:
            self._view = bank_view_separate_frames.MainWindow("Demo MVC - Bank Simulator")
        else:
            self._view = bank_view.MainWindow("Demo MVC - Bank Simulator")

        # Note that this controller can conceptually handle many customers and workplaces,
        # even though the current view implementations can't...

        self._customers = []
        self._workplaces = []

        # Here is the place in the controller where we restore the app state from storage,
        # or (as in this case) create from scratch

        self._customers.append(CustomerModel("Fred Nerks"))

        self._bank = BankModel()
        self._bank.CreateAccountFor(self._customers[0])

        self._view.AddBank(self._bank)
        self._view.AddCustomer(self._customers[0])

    def OnAppEvent(self, event, value=None):
        if event == AppEvents.APP_EXIT:
            self._log.info("MVC Controller: exit requested.")
            # do any necessary state saving...
            # ... then:
            sys.exit()
        elif event == AppEvents.APP_ADD_WORKPLACE:
            self._log.info("Main Controller: Add workplace requested...")
            self._workplaces.append(WorkplaceModel("Workplace %d" % (len(self._workplaces)+1) ))
            # Note: here the controller is implementing application business logic driving interactions between models
            new_workplace = self._workplaces[-1]
            for customer in self._customers:
                if customer.AcceptEmployment(new_workplace):
                    new_workplace.AddEmployee(customer)
            self._view.AddWorkplace(new_workplace)

        elif event == AppEvents.CUSTOMER_DEPOSIT:
            (the_customer, the_amount) = value
            self._log.info("customer deposit funds requested(%s)..." % the_customer.name)
            the_customer.DepositFunds(the_amount)
        elif event == AppEvents.CUSTOMER_WITHDRAWAL:
            (the_customer, the_amount) = value
            self._log.info("customer withdraw funds requested(%s)..." % the_customer.name)
            the_customer.WithdrawFunds(the_amount)
        elif event == AppEvents.CUSTOMER_EARN:
            the_customer = value
            self._log.info("customer earn requested(%s)..." % the_customer.name)
            the_customer.Work()

        elif event == AppEvents.PERSON_WORK:
            the_person = value
            self._log.info("request for customer %s to work ..." % customer.name)
            the_person.Work()
        elif event == AppEvents.EARN_REVENUE:
            self._log.info("request for sales revenue payment ...")
            the_workplace = value
            the_workplace.EarnFromSales()
        else:
            raise Exception("Unknown APP_EVENT: %s" % event)

#################
#
#  Models
#

class AccountModel:
    def __init__(self, owner, bank):
        self._balance = 0
        self._owner = owner
        self._bank = bank

    def AddMoney(self, amount):
        self._balance += amount
        self._bank.ReceiveMoney(amount)

    def RemoveMoney(self, amount):
        withdrawal_amount = min(amount, self._balance)  # they can't take out more than their account balance
        pay_amount = self._bank.PayMoney(withdrawal_amount)
        self._balance -= pay_amount
        return pay_amount


class CustomerModel:
    def __init__(self, name):
        self._log = logging.getLogger("MVC Logger")
        self._log.info("Customer %s logging started" % name)
        self.name = name

        self._cash = 0
        self._account = None
        self._employer = None

    def GetAccount(self, account):
        self._account = account

    def CashInHand(self):
        return self._cash

    def AcceptEmployment(self, workplace):
        self._employer = workplace
        self._log.info("%s accepted employment at %s" % (self.name, workplace.name))
        return True

    def Work(self):
        if self._employer:
            self._cash += self._employer.RequestPay(self)
            pub.sendMessage("CUSTOMER_BALANCE_EVENT", value = self)
        else:
            self._log.info("%s cant work, not employed" % self.name)

    def DepositFunds(self, amount):
        deposit_amount = min(amount, self._cash) # can't deposit more than we have
        self._cash -= deposit_amount
        self._account.AddMoney(deposit_amount)
        pub.sendMessage("CUSTOMER_BALANCE_EVENT", value = self)

    def WithdrawFunds(self, amount):
        amount_received = self._account.RemoveMoney(amount)
        self._cash += amount_received
        pub.sendMessage("CUSTOMER_BALANCE_EVENT", value = self)


class BankModel:
    def __init__(self):
        self._funds = 0
        self._accounts = {}

    def Funds(self):
        return self._funds

    def CreateAccountFor(self, owner):
        new_account = AccountModel(owner, self)
        self._accounts[owner.name] = new_account
        owner.GetAccount(new_account)

    def PayMoney(self, amount):
        paid = min(self._funds, amount)
        self._funds -= paid
        pub.sendMessage("BANK_BALANCE_EVENT")
        return paid

    def ReceiveMoney(self, amount):
        self._funds += amount
        pub.sendMessage("BANK_BALANCE_EVENT")


class WorkplaceModel:
    def __init__(self, name):
        self.name = name

        self._employees = []
        self._standardWage = 10

        self._funds = 0
        self._salesRevenue = 20

    def AddEmployee(self, employee):
        self._employees.append(employee)

    def EarnFromSales(self):
        self._funds += self._salesRevenue
        pub.sendMessage("WORKPLACE_BALANCE_EVENT")

    def Funds(self):
        return self._funds

    def RequestPay(self, employee):
        # (should check if employee is legit)
        paid = min(self._funds, self._standardWage)
        self._funds -= paid
        pub.sendMessage("WORKPLACE_BALANCE_EVENT")
        return paid

##############
#
#

logging.basicConfig(level=logging.INFO)

view_separate_frames = False

if len(sys.argv) > 1:
    if sys.argv[1] == "view-separate-frames":
        view_separate_frames = True

app = wx.App()
controller = Controller(view_separate_frames)
app.MainLoop()

文件bank_view.py

import wx
from enum import Enum

from wx.lib.pubsub import setupkwargs
from wx.lib.pubsub import pub

import logging

#####
#   The control events that the Controller can process
#   Usually this would be in a module imported by each of M, V and C
#   These are the possible values for the "event" parameter of an APP_EVENT message

class AppEvents(Enum):
    APP_EXIT = 0
    APP_ADD_WORKPLACE = 1
    APP_ADD_CUSTOMER = 2
    CUSTOMER_DEPOSIT = 3
    CUSTOMER_WITHDRAWAL = 4
    CUSTOMER_EARN = 5
    PERSON_WORK = 6
    EARN_REVENUE = 7


#################
#
#   View
#

class MainWindow(wx.Frame):

    def __init__(self,  title):
        wx.Frame.__init__(self, None, -1, title)

        self._log = logging.getLogger("MVC Logger")
        self._log.info("MVC View - separate workspace: starting...")

        self._bankStatusDisplay = None
        self._customerUIs = {}
        self._workplaceUIs = {}

        # this is where we will put display elements - it's up to the controller to add them
        self._sizer = wx.BoxSizer(wx.HORIZONTAL)
        self.SetSizer(self._sizer)

        # but we do need one button immediately...
        add_workplace_button = wx.Button(self, label="Add Workplace")
        self._sizer.Add(add_workplace_button)
        self._sizer.Layout()

        self.Bind(wx.EVT_BUTTON, self._OnAddWorkplaceClick, add_workplace_button)

        # These are the events that cause us to update our display
        pub.subscribe(self._OnCustomerBalanceChange, "CUSTOMER_BALANCE_EVENT")
        pub.subscribe(self._OnBankBalanceChange, "BANK_BALANCE_EVENT")

        self.Show()

    def _OnAddWorkplaceClick(self, event):
        pub.sendMessage("APP_EVENT", event = AppEvents.APP_ADD_WORKPLACE)

    def AddWorkplace(self, workplace):
        self._workplaceUIs[workplace.name] = the_ui = WorkplaceInterface(self, workplace)
        self._sizer.Add(the_ui)
        self._sizer.Layout()

    def AddBank(self, bank):
        if not(self._bankStatusDisplay):
            self._bankStatusDisplay = BankStatusDisplay(self, bank)        
            self._sizer.Add(self._bankStatusDisplay)
            self._sizer.Layout()
        else:
            raise Exception("We can only handle one bank at the moment")

    def AddCustomer(self, customer):
        self._customerUIs[customer.name] = the_ui = CustomerInterface(self, customer)
        self._sizer.Add(the_ui)
        self._sizer.Layout()

    def _OnCustomerBalanceChange(self, value):
        customer = value
        self._customerUIs[customer.name].UpdateBalance()

    def _OnBankBalanceChange(self):
        self._bankStatusDisplay.Update()


class BankStatusDisplay(wx.Panel):
    def __init__(self, parent, bank):
        wx.Panel.__init__(self, parent, style = wx.RAISED_BORDER)

        self._bank = bank

        sizer = wx.BoxSizer(wx.VERTICAL)
        label = wx.StaticText(self, label="Bank Funds")

        balance_display = wx.TextCtrl(self)
        balance_display.SetEditable(False)
        balance_display.SetValue('$' + str(bank.Funds()))

        sizer.Add(label, 0, wx.EXPAND | wx.ALL)
        sizer.Add(balance_display, 0, wx.EXPAND | wx.ALL)

        self.SetSizer(sizer)        

        self._balanceDisplay = balance_display

    def Update(self):
        self._balanceDisplay.SetValue('$' + str(self._bank.Funds()))


class CustomerInterface(wx.Panel):
    def __init__(self, parent, customer):
        wx.Panel.__init__(self, parent, style = wx.RAISED_BORDER)

        self._customer = customer
        self._standardTransaction = 5 # how much customers try to deposit and withdraw

        sizer = wx.BoxSizer(wx.VERTICAL)
        label = wx.StaticText(self, label=customer.name)

        self._balanceDisplay = wx.TextCtrl(self)
        self._balanceDisplay.SetEditable(False)
        self._balanceDisplay.SetValue('$' + str(customer.CashInHand()))

        deposit_button = wx.Button(self, label="Deposit $" + str(self._standardTransaction))
        withdraw_button = wx.Button(self, label="Withdraw $" + str(self._standardTransaction))
        earn_button = wx.Button(self, label="Earn Money")

        sizer.Add(label, 0, wx.EXPAND | wx.ALL)
        sizer.Add(self._balanceDisplay, 0, wx.EXPAND | wx.ALL)

        sizer.Add(deposit_button, 0, wx.EXPAND | wx.ALL)
        sizer.Add(withdraw_button, 0, wx.EXPAND | wx.ALL)        
        sizer.Add(earn_button, 0, wx.EXPAND | wx.ALL)

        self.Bind(wx.EVT_BUTTON, self._OnDepositClick, deposit_button)
        self.Bind(wx.EVT_BUTTON, self._OnWithdrawClick, withdraw_button)
        self.Bind(wx.EVT_BUTTON, self._OnEarnClick, earn_button)

        self.SetSizer(sizer)
        self.Show()

    def _OnDepositClick(self, event):
        pub.sendMessage("APP_EVENT", event = AppEvents.CUSTOMER_DEPOSIT, value = (self._customer, self._standardTransaction))

    def _OnWithdrawClick(self, event):
        pub.sendMessage("APP_EVENT", event = AppEvents.CUSTOMER_WITHDRAWAL, value = (self._customer, self._standardTransaction))

    def _OnEarnClick(self, event):
        pub.sendMessage("APP_EVENT", event = AppEvents.CUSTOMER_EARN, value = self._customer)

    def UpdateBalance(self):
        self._balanceDisplay.SetValue('$' + str(self._customer.CashInHand()))


class WorkplaceInterface(wx.Panel):
    def __init__(self, parent, workplace):
        wx.Panel.__init__(self, parent, style = wx.RAISED_BORDER)

        self._workplace = workplace

        sizer = wx.BoxSizer(wx.VERTICAL)
        label = wx.StaticText(self, label="Workplace Funds")

        self._balanceDisplay = wx.TextCtrl(self)
        self._balanceDisplay.SetEditable(False)
        self._balanceDisplay.SetValue('$' + str(workplace.Funds()))

        revenue_button = wx.Button(self, label="Earn Revenue")

        sizer.Add(label, 0, wx.EXPAND | wx.ALL)
        sizer.Add(self._balanceDisplay, 0, wx.EXPAND | wx.ALL)

        sizer.Add(revenue_button, 0, wx.EXPAND | wx.ALL)

        self.SetSizer(sizer)
        self.Show()

        self.Bind(wx.EVT_BUTTON, self._OnRevenueClick, revenue_button)

        pub.subscribe(self._OnBalanceChange, "WORKPLACE_BALANCE_EVENT")

    def _OnRevenueClick(self, event):
        pub.sendMessage("APP_EVENT", event = AppEvents.EARN_REVENUE, value = (self._workplace))

    def _OnBalanceChange(self):
        self._balanceDisplay.SetValue('$' + str(self._workplace.Funds()))

文件:bank_view_separate_frames.py

import wx
from enum import Enum

from wx.lib.pubsub import setupkwargs
from wx.lib.pubsub import pub

import logging

#####
#   The control events that the Controller can process
#   Usually this would be in a module imported by each of M, V and C
#   These are the possible values for the "event" parameter of an APP_EVENT message

class AppEvents(Enum):
    APP_EXIT = 0
    APP_ADD_WORKPLACE = 1
    APP_ADD_CUSTOMER = 2
    CUSTOMER_DEPOSIT = 3
    CUSTOMER_WITHDRAWAL = 4
    CUSTOMER_EARN = 5
    PERSON_WORK = 6
    EARN_REVENUE = 7


#################
#
#   View
#

class MainWindow(wx.Frame):

    def __init__(self,  title):
        wx.Frame.__init__(self, None, -1, title)

        self._log = logging.getLogger("MVC Logger")
        self._log.info("MVC View - separate workspace: starting...")

        self._bankStatusDisplay = None
        self._customerUIs = {}
        self._workplaceUIs = {}

        # this is where we will put display elements - it's up to the controller to add them
        self._sizer = wx.BoxSizer(wx.HORIZONTAL)
        self.SetSizer(self._sizer)

        # but we do need one button immediately...
        add_workplace_button = wx.Button(self, label="Add Workplace")
        self._sizer.Add(add_workplace_button)
        self._sizer.Layout()

        self.Bind(wx.EVT_BUTTON, self._OnAddWorkplaceClick, add_workplace_button)

        # These are the events that cause us to update our display
        pub.subscribe(self._OnCustomerBalanceChange, "CUSTOMER_BALANCE_EVENT")
        pub.subscribe(self._OnBankBalanceChange, "BANK_BALANCE_EVENT")

        self.Show()

    def _OnAddWorkplaceClick(self, event):
        pub.sendMessage("APP_EVENT", event = AppEvents.APP_ADD_WORKPLACE)

    def AddWorkplace(self, workplace):
        self._workplaceUIs[workplace.name] = WorkplaceInterface(self, workplace)

    def AddBank(self, bank):
        if not(self._bankStatusDisplay):
            self._bankStatusDisplay = BankStatusDisplay(self, bank)        
            self._sizer.Add(self._bankStatusDisplay)
            self._sizer.Layout()
        else:
            raise Exception("We can only handle one bank at the moment")

    def AddCustomer(self, customer):
        self._customerUIs[customer.name] = CustomerInterface(self, customer)

    def AddWorkplace(self, workplace):
        self._theWorkplaceUI = WorkplaceInterface(workplace)

    def _OnCustomerBalanceChange(self, value):
        customer = value
        self._customerUIs[customer.name].UpdateBalance()

    def _OnBankBalanceChange(self):
        self._bankStatusDisplay.Update()


class BankStatusDisplay(wx.Panel):
    def __init__(self, parent, bank):
        wx.Panel.__init__(self, parent, style = wx.RAISED_BORDER)

        self._bank = bank

        sizer = wx.BoxSizer(wx.VERTICAL)
        label = wx.StaticText(self, label="Bank Funds")

        balance_display = wx.TextCtrl(self)
        balance_display.SetEditable(False)
        balance_display.SetValue('$' + str(bank.Funds()))

        sizer.Add(label, 0, wx.EXPAND | wx.ALL)
        sizer.Add(balance_display, 0, wx.EXPAND | wx.ALL)

        self.SetSizer(sizer)        

        self._balanceDisplay = balance_display

    def Update(self):
        self._balanceDisplay.SetValue('$' + str(self._bank.Funds()))


class CustomerInterface(wx.Frame):
    def __init__(self, parent, customer):
        wx.Frame.__init__(self, None, -1, customer.name, size = (200,300))

        self._customer = customer
        self._standardTransaction = 5 # how much customers try to deposit and withdraw

        sizer = wx.BoxSizer(wx.VERTICAL)
        label = wx.StaticText(self, label=customer.name)

        self._balanceDisplay = wx.TextCtrl(self)
        self._balanceDisplay.SetEditable(False)
        self._balanceDisplay.SetValue('$' + str(customer.CashInHand()))

        deposit_button = wx.Button(self, label="Deposit $" + str(self._standardTransaction))
        withdraw_button = wx.Button(self, label="Withdraw $" + str(self._standardTransaction))
        earn_button = wx.Button(self, label="Earn Money")

        sizer.Add(label, 0, wx.EXPAND | wx.ALL)
        sizer.Add(self._balanceDisplay, 0, wx.EXPAND | wx.ALL)

        sizer.Add(deposit_button, 0, wx.EXPAND | wx.ALL)
        sizer.Add(withdraw_button, 0, wx.EXPAND | wx.ALL)        
        sizer.Add(earn_button, 0, wx.EXPAND | wx.ALL)

        self.Bind(wx.EVT_BUTTON, self._OnDepositClick, deposit_button)
        self.Bind(wx.EVT_BUTTON, self._OnWithdrawClick, withdraw_button)
        self.Bind(wx.EVT_BUTTON, self._OnEarnClick, earn_button)

        self.SetSizer(sizer)
        self.Show()

    def _OnDepositClick(self, event):
        pub.sendMessage("APP_EVENT", event = AppEvents.CUSTOMER_DEPOSIT, value = (self._customer, self._standardTransaction))

    def _OnWithdrawClick(self, event):
        pub.sendMessage("APP_EVENT", event = AppEvents.CUSTOMER_WITHDRAWAL, value = (self._customer, self._standardTransaction))

    def _OnEarnClick(self, event):
        pub.sendMessage("APP_EVENT", event = AppEvents.CUSTOMER_EARN, value = self._customer)

    def UpdateBalance(self):
        self._balanceDisplay.SetValue('$' + str(self._customer.CashInHand()))


class WorkplaceInterface(wx.Frame):
    def __init__(self, workplace):
        wx.Frame.__init__(self, None, -1, workplace.name, size = (200,200))

        self._workplace = workplace

        self._panel = wx.Panel(self, style = wx.RAISED_BORDER)

        sizer = wx.BoxSizer(wx.VERTICAL)
        label = wx.StaticText(self._panel, label="Funds")

        self._balanceDisplay = wx.TextCtrl(self._panel)
        self._balanceDisplay.SetEditable(False)
        self._balanceDisplay.SetValue('$' + str(workplace.Funds()))

        revenue_button = wx.Button(self._panel, label="Earn Revenue")

        sizer.Add(label, 0, wx.EXPAND | wx.ALL)
        sizer.Add(self._balanceDisplay, 0, wx.EXPAND | wx.ALL)

        sizer.Add(revenue_button, 0, wx.EXPAND | wx.ALL)

        self._panel.SetSizer(sizer)

        self.Bind(wx.EVT_BUTTON, self._OnRevenueClick, revenue_button)

        pub.subscribe(self._OnBalanceChange, "WORKPLACE_BALANCE_EVENT")

        self.Show()

    def _OnRevenueClick(self, event):
        pub.sendMessage("APP_EVENT", event = AppEvents.EARN_REVENUE, value = (self._workplace))

    def _OnBalanceChange(self):
        self._balanceDisplay.SetValue('$' + str(self._workplace.Funds()))

散记:

  • 我已将模型类命名为“ ThingoModel”。通常,您只是将它们命名为Thingo-暗含了“模型”,但我这样做是为了希望在此处清晰明了。

  • 同样,选择视图组件的名称以强调其视图角色。

  • 此示例显示视图的组件,该组件通过pubsub消息(“应用程序事件”)通知控制器用户所请求的内容

  • 它显示了模型,这些模型使用pubsub消息(模型特定的事件)向“关心的人”(视图)通知可能需要更改视图的事件。

  • 它让Controller告诉View使用方法调用做什么

  • 非常小心不要直接拥有View访问模型。视图具有对模型的引用(对模型的引用),以显示模型中的信息。在C ++中,这些将是视图无法更改的常量。在python中,您所能做的就是规矩以确保View读取模型中的内容,但将所有内容通知给Controller

  • 此代码扩展为非常轻松地支持多个客户。您应该能够在控制器中创建更多的东西,并且(手指交叉)它们将被处理

  • 该代码假定只有一个银行。

我已经使用这种基本模式编写了几个大型wxpython应用程序。当我开始时,我将这些应用程序中的第一个作为MVC-P中的实验来构建。当意外情况迫使我完全重做GUI的布局时,我完全转换为这种方法。因为在我的视图中没有业务逻辑,所以这完全是易于处理的,并且重新完成的应用程序可用相对较快,并且功能退化很少。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

如何使控制器保持活动状态

来自分类Dev

关闭模态视图控制器时如何保持呈现视图控制器的方向?

来自分类Dev

如何使Glide保持连接存活?

来自分类Dev

如何保持android进程存活

来自分类Dev

如何模拟控制器

来自分类Dev

如何保持石英.net的调度程序存活?

来自分类Dev

如何从uiviewcontainer的控制器获取父控制器

来自分类Dev

Swift +故事板:如何保持强大的参考力来显示segue控制器?

来自分类Dev

切换视图控制器后如何保持从iCloud(CloudKit)加载的数据

来自分类Dev

切换视图控制器后如何保持从iCloud(CloudKit)加载的数据

来自分类Dev

AngularJS:如何在保持控制器逻辑的同时更新服务属性?

来自分类Dev

如何将控制器保持在一个方向?

来自分类Dev

在 Laravel 中创建通用控制器时如何保持 DRY?

来自分类Dev

保持微控制器外围驱动器独立

来自分类Dev

如何在保持标签栏的同时将子视图控制器添加到选项卡式视图控制器?

来自分类Dev

在视图控制器之间保持子上下文

来自分类Dev

ui-router使控制器保持活动状态

来自分类Dev

保持导航控制器的状态,仅更改视图

来自分类Dev

在视图控制器之间保持子上下文

来自分类Dev

在AngularJS中使不同控制器中的变量保持同步

来自分类Dev

与 pushview 控制器保持相同的导航栏颜色

来自分类Dev

保持任务在视图控制器之间运行

来自分类Dev

如何从控制器访问模型?

来自分类Dev

如何从控制器访问工厂

来自分类Dev

如何从控制器调用视图组件

来自分类Dev

如何从presentView控制器返回RootViewController?

来自分类Dev

AngularJS:控制器之间如何通信?

来自分类Dev

如何从角度控制器打开模态

来自分类Dev

如何构造控制器和服务

Related 相关文章

  1. 1

    如何使控制器保持活动状态

  2. 2

    关闭模态视图控制器时如何保持呈现视图控制器的方向?

  3. 3

    如何使Glide保持连接存活?

  4. 4

    如何保持android进程存活

  5. 5

    如何模拟控制器

  6. 6

    如何保持石英.net的调度程序存活?

  7. 7

    如何从uiviewcontainer的控制器获取父控制器

  8. 8

    Swift +故事板:如何保持强大的参考力来显示segue控制器?

  9. 9

    切换视图控制器后如何保持从iCloud(CloudKit)加载的数据

  10. 10

    切换视图控制器后如何保持从iCloud(CloudKit)加载的数据

  11. 11

    AngularJS:如何在保持控制器逻辑的同时更新服务属性?

  12. 12

    如何将控制器保持在一个方向?

  13. 13

    在 Laravel 中创建通用控制器时如何保持 DRY?

  14. 14

    保持微控制器外围驱动器独立

  15. 15

    如何在保持标签栏的同时将子视图控制器添加到选项卡式视图控制器?

  16. 16

    在视图控制器之间保持子上下文

  17. 17

    ui-router使控制器保持活动状态

  18. 18

    保持导航控制器的状态,仅更改视图

  19. 19

    在视图控制器之间保持子上下文

  20. 20

    在AngularJS中使不同控制器中的变量保持同步

  21. 21

    与 pushview 控制器保持相同的导航栏颜色

  22. 22

    保持任务在视图控制器之间运行

  23. 23

    如何从控制器访问模型?

  24. 24

    如何从控制器访问工厂

  25. 25

    如何从控制器调用视图组件

  26. 26

    如何从presentView控制器返回RootViewController?

  27. 27

    AngularJS:控制器之间如何通信?

  28. 28

    如何从角度控制器打开模态

  29. 29

    如何构造控制器和服务

热门标签

归档