我正在用Python实现GUI应用程序,我想使用MVC模式。我努力了解MVC的工作原理,因此我开发了一个小型GUI应用程序以试图更好地理解它,然后将概念扩展到我的真实应用程序中。
该应用程序非常简单,请参见附图。第一行包含一个文本空间和一个“写”按钮,在这里我将在文本空间中输入一些文本,并通过按下按钮将其写到excel文件中。 第二行具有类似的配置,但是通过按“读取”按钮,它将从Excel读取单元格并将其显示在文本框中。该应用程序非常简单,它需要突出显示查看器到模型的控件,反之亦然。 这是图片:
{{3}}
代码如下:
view.py
from openpyxl import Workbook
from openpyxl import load_workbook
class model():
#----------------------------------------------------------------------
def __init__(self):
self.path = ""
self.book = ""
self.sheet_index= ""
self.sheet = ""
def setPath(self,path):
self.path = path
def setWorkSheetIndex(self, index):
self.sheet_index = index
def loadBookandSheet(self):
self.book = load_workbook(self.path)
self.sheet = self.book.worksheets[0]
def write(self, string):
self.sheet.cell(2,1).value = string
self.book.save(self.path)
def read(self):
return self.sheet.cell(1,1).value
model.py
from view import view
from model import model
import wx
class controller():
#----------------------------------------------------------------------
def __init__(self, view, model, app):
self.view = view
self.controller = model
self.app = app
self.view.Show()
self.app.MainLoop()
def setPath(self,path):
self.path = path
def setWorkSheetIndex(self, index):
self.sheet_index = index
if __name__ == "__main__":
app = wx.App(False)
frame = view()
model_ = model()
controller_ = controller(frame, model_, app)
到目前为止,一切都很好。该模型可以读写excel文件,并且视图类显示GUI,并在CML上对其进行单独测试,所有这些都可以正常工作。 接下来是控制器类,正如我所阅读的,它需要同时具有视图和模型的实例,以便它可以处理它们之间的通信,同时实现程序的整个逻辑。例如,用户将按下GUI上的“读取”按钮,GUI将此信息传递给控制器,控制器调用模型的“读取”方法,然后控制器更新GUI的显示。
controller.py
const starCluster = <div><FaStar /><FaStar /><FaStar /></div>
const starColor = (props) => {
let rows = [];
let starClr = "";
props.stardata.map((sta, i) => {
if (sta.rating > 1 && sta.rating <= 1.9) {
starClr = <div className="oneStar">{ starCluster }</div>;
}
if (sta.rating >=2 && sta.rating <= 2.9) {
starClr = <div className="twoStar">{ starCluster }</div>
}
rows.push(<li key={i}>
{sta.name}
{starClr}
</li>)
});
return (
<div>
<ul>
{rows}
</ul>
</div>
)
}
这是我的问题。由于“控制器”包含“模型”,因此我可以轻松地在它们之间进行通信。 “控制器”还包含“视图”,因此一旦我获得了模型中的数据,便可以在控制器类中实现一种方法来更新GUI中的显示。
但是,如何从视图与控制器进行通讯?如何实现“用户按下读取按钮,控制器调用模型的读取方法?”我看不到使用事件将信息从GUI传递到控制器类的任何方式。
谢谢
答案 0 :(得分:0)
找到了解决方案,希望对您有所帮助。这就是说,据我所知,MVC可以通过多种方式实现,因此可能不会更有效,但它可以工作。我使用发布者-订阅者来进行视图->控制器通信,以发送事件和数据。控制器->模型的通信非常简单,只需调用方法即可,最后,模型再次使用Publisher-> subscriber更新视图的状态。遵循代码。请记住,输入用户输入时,需要按Enter键以接受文本。肯定有更好的解决方案,但这不是我的目的。遵循代码:
view.py
<Logger name="com.itms" level="debug" additivity="true">
<AppenderRef ref="XmlFileAppender"/>
</Logger>
model.py
import wx
from pubsub import pub
class view(wx.Frame):
#----------------------------------------------------------------------
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY, "mvc")
# Add a panel so it looks the correct on all platforms
panel = wx.Panel(self, wx.ID_ANY)
box = wx.BoxSizer(wx.VERTICAL)
box_h = wx.BoxSizer(wx.HORIZONTAL)
self.txt = wx.TextCtrl(panel, style=wx.TE_PROCESS_ENTER)
self.txt.SetFocus()
self.txt.Bind(wx.EVT_TEXT_ENTER, self.OnEnter)
box_h.Add(self.txt, 1, wx.EXPAND|wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 5)
self.btn_write = wx.Button(panel,-1,"Write")
self.btn_write.Bind(wx.EVT_BUTTON, self.onWrite)
box_h.Add(self.btn_write,1,wx.EXPAND|wx.ALIGN_CENTER_HORIZONTAL|wx.ALL,5)
box.Add(box_h,1,wx.EXPAND|wx.ALIGN_CENTER_HORIZONTAL|wx.ALL,5)
box_h_2 = wx.BoxSizer(wx.HORIZONTAL)
self.btn_read = wx.Button(panel,-1,"Read")
self.btn_read.Bind(wx.EVT_BUTTON, self.onRead)
box_h_2.Add(self.btn_read,1,wx.EXPAND|wx.ALIGN_CENTER_HORIZONTAL|wx.ALL,5)
self.text_display = wx.StaticText(panel, label="", style=wx.TE_READONLY|wx.BORDER_SUNKEN)
self.text_display.SetBackgroundColour((255,255,255)) # set text back color
box_h_2.Add(self.text_display,1,wx.EXPAND|wx.ALIGN_CENTER_HORIZONTAL|wx.ALL,5)
box.Add(box_h_2,1,wx.EXPAND|wx.ALIGN_CENTER_HORIZONTAL|wx.ALL,5)
panel.SetSizer(box)
self.text = ""
pub.subscribe(self.updateDisplay, 'display_channel')
##########################################################
def updateDisplay(self, value):
self.text_display.SetLabel(str(value))
def OnEnter(self, event):
self.text = self.txt.GetValue()
def onWrite(self, event):
pub.sendMessage("write_channel", write=self.text)
def onRead(self, event):
pub.sendMessage("read_channel", readValue=1)
##########################################################
# Run the program
if __name__ == "__main__":
app = wx.App(False)
frame = view()
frame.Show()
app.MainLoop()
controller.py
from openpyxl import Workbook
from openpyxl import load_workbook
from pubsub import pub
class model():
#----------------------------------------------------------------------
def __init__(self):
self.path = ""
self.book = ""
self.sheet_index= ""
self.sheet = ""
def setWorkSheetIndex(self, index):
self.sheet_index = index
def loadBookandSheet(self):
self.book = load_workbook("myfile.xlsx")
self.sheet = self.book.worksheets[0]
def write(self, string_text):
print "string " + string_text
self.sheet.cell(2,1).value = string_text
self.book.save("myfile.xlsx")
def read(self):
value_ = self.sheet.cell(1,1).value
pub.sendMessage("display_channel", value = value_)