在MVC中查看到控制器的通讯

时间:2018-08-16 16:24:14

标签: python model-view-controller

我正在用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传递到控制器类的任何方式。

谢谢

1 个答案:

答案 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_)