我正在尝试使用 this link 实现 MVC 模式.一切正常,直到我用它的 Controller 创建了第二帧。第一帧的 Controller 仍然存在,因为代码被阻止了:
app.MainLoop()
但是当第二个 Controller (在按钮事件中创建)时,它将被 GC 处理,因为它已经脱离上下文。我不想将 Controller 引用到 View ,因为我想尝试被动 View 方法,即 View 是愚蠢的, Controller 更新 View ,而且它会导致循环引用。
这是我调用 Controller 的方式:
def OnClick(self, evt):
controller = MyController2()
如果我像这样将 Controller 引用到父 Controller :
def OnClick(self, evt):
self.controller = MyController2()
Controller 还活着,但我关闭第二帧后 Controller 不会还活着吗?如何让第二个 Controller 保持事件状态,但在其 View 关闭后仍然可以进行 GC?此外,我想保持 View 不受任何逻辑影响,因为它已经包含了小部件定义(我在 1 个框架中有很多小部件)。
对于我糟糕的英语,我们将不胜感激和抱歉。
编辑:
这是我收集垃圾的 Controller 示例。此示例使用 blinker 而不是 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()
如您所见, child 的按钮没有正常工作,因为它的 Controller 已经被垃圾回收(没有人引用 Controller )。我尝试了一些解决方案,例如:
在父 Controller 中引用子 Controller 。 当 child 关闭时,子 Controller 将仍然存在,除非我手动删除它或用新 Controller 替换 Controller (重新打开子窗口)。如果 Controller 保存大量数据,这尤其糟糕。
Controller 和 View 之间的循环引用(在 Controller -> View 上使用弱引用)。 这是我最好的选择,但我想避免循环引用。
那么,我应该在哪里引用子 Controller 以使其保持事件状态?
请您参考如下方法:
好吧,这是一个很大的话题:如何在wxPython中做MVC。没有一个正确答案。对于您选择的任何答案,当您试图虔诚地遵循设计模式时,您将遇到困难的选择。
一些例子不够复杂,无法处理其中的一些问题。这是我创建的一个示例,用于尝试说明适合我的方法。
可以看到View元素的创建和 Controller 之间没有耦合, Controller 拥有“设置应用程序”的逻辑。 View 是真正被动的 - 它的元素仅在需要满足 Controller 操作时才存在。
我添加了两个 View 实现,您可以使用命令行参数在它们之间进行选择。我想表明的是,这是对您是否实现了良好的 Controller / View 分离的真实测试——您应该能够插入不同的 View 实现而根本不必更改 Controller 。 Controller 取决于业务逻辑(包括应用程序中可能发生的事件类型)和模型 API。它不依赖于 View 中的任何内容。
文件: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 - 隐含了“模型”,但我这样做是为了清楚起见。
同样,选择 View 组件的名称是为了强调它们的 View 角色。
此示例显示了 View 的组件通知 Controller 用户通过 pubsub 消息(“应用程序事件”)请求的内容
它显示模型使用 pubsub 消息(模型特定事件)通知“谁关心”( View )可能需要更改 View 的事件。
它让 Controller 告诉 View 使用方法调用做什么
不要让 View 直接访问模型是非常小心的。 View 具有模型的句柄(引用)以显示来自模型的信息。在 C++ 中,这些将是 View 无法更改的 const thingoes。在 python 中,你所能做的就是遵守纪律,确保 View 读取来自模型的内容,但将所有内容通知给 Controller
此代码很容易扩展到支持多个客户。您应该能够在 Controller 中创建更多内容并且(祈祷)它们会被处理
代码假设只有一家银行。
我已经使用这个基本模式编写了几个大型 wxpython 应用程序。当我开始时,我构建了这些应用程序中的第一个作为 MVC-P 中的实验。当意外情况迫使我完全重做 GUI 的布局时,我完全转变为这种方法。因为我的 View 中没有业务逻辑,所以这完全易于处理,并且重新完成的应用程序相对较快可用并且几乎没有功能回归。
