PyQt 和 MVC 模式 [英] PyQt and MVC-pattern

查看:113
本文介绍了PyQt 和 MVC 模式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 PyQt 设计一个 MVC 模式.我想将所有程序分成 3 部分:

  1. 从所有 Qt 类(模型)中抽象出来的类
  2. 从模型向 Qt 应用(控制器)提供数据的类
  3. Qt 应用程序本身带有定义的方法 SignalsToSlots,将信号与控制器连接起来.

这是最佳选择吗?PyQt 开发中推荐使用什么方案?

解决方案

你应该做的第一件事是使用 Qt4 设计器来设计你的 gui 并使用 pyuic4 来生成你的 Python GUI.这将是您的观点,您永远不要手动编辑这些 python 文件.始终使用设计器进行更改,这可确保您的视图与模型和控件分开.

对于控制元素,创建一个从基本 gui 小部件(例如 QMainWindow)继承的中心类.然后,该对象将包含一个成员 ui,即您刚刚生成的视图对象.

这是教程中的一个例子>

2013 年更新:这是关于 PyQt 和 MVC 模型的最新教程PyQt MVC 教程系列

导入系统从 PyQt4 导入 QtCore、QtGui从 edytor 导入 Ui_notepad类 StartQT4(QtGui.QMainWindow):def __init__(self, parent=None):QtGui.QWidget.__init__(self, parent)self.ui = Ui_notepad()self.ui.setupUi(self)如果 __name__ == "__main__":app = QtGui.QApplication(sys.argv)myapp = StartQT4()myapp.show()sys.exit(app.exec_())

上面例子的关键是控制器包含了ui,并没有直接继承它.控制器将负责为您的 gui 管理信号槽连接并为您的数据模型提供接口.

为了描述我们需要一个示例的模型部分,假设您的项目是创建一个电影收藏数据库.该模型将包括代表单个电影的内部对象,以及代表电影列表的对象.您可以控制从视图中输入的数据并捕获信号,然后在要求模型自我更新之前验证它们.这部分很关键,如果可能的话,控制器不应该直接访问模型,它应该要求模型访问自己.

这是这个交互的一个小例子(未经测试,可能有一些错别字):

class Movie():def __init__(self,title=None,year=None,genre=None):self.title=titleself.year=年self.genre=流派def update(self,title=None,year=None,genre=None):self.title=titleself.year=年self.genre=流派def to_xml(self,title=None,date=None,genre=None):pass #not 以这个为例!#当控制器尝试更新它应该使用更新功能movie1.update("Manos Hands Of Fate",1966,"Awesome")#不要通过直接访问设置,你的控制器不应该那么深movie1.title="坏主意" #不想要!

在 MVC 中集中访问也很重要,比如用户可以通过在屏幕上双击标题来更改标题,或者通过单击标题字段旁边的编辑,这两个界面都应该最终使用相同的方法进行更改.我的意思并不是每个人都调用movie.update_title(title).我的意思是两个信号都应该在控制器中使用相同的方法.

尽量使视图和控制器之间的所有关系多对一.意思是,您有 5 种方法可以更改 gui 中的某些内容,控制器中有 1 种方法来处理此问题.如果插槽不完全兼容,则为每个方法创建方法,然后调用一个方法.如果您为 5 种视图样式解决了 5 次问题,那么确实没有理由将视图与控件分开.此外,由于您现在只有一种方法可以在控制器中执行某些操作,因此您可以在控制和模型之间建立良好的 1 对 1 关系.

就让您的模型与 Qt 完全分离而言,这并不是真正必要的,而且实际上可能会让您的生活更加艰难.在你的模型中使用 QStrings 之类的东西会很方便,如果在另一个应用程序中你不想要 Gui 的开销,但希望模型只导入 QtCore.希望这会有所帮助!

I am trying to design an MVC-pattern with PyQt. I want to split all programs into 3 parts:

  1. classes abstracted from all Qt classes (model)
  2. classes providing data from the model to a Qt app (controller)
  3. the Qt app itself with defined method SignalsToSlots that connects signals with controller.

Is this optimally? What scheme is recommended for use in PyQt development?

解决方案

One of the first things you should do is use Qt4 designer to design your gui and use pyuic4 to generate your python GUI. This will be your view, you NEVER edit these python files by hand. Always make changes using designer, this ensures your View is separate from your model and control.

For the control element, create a central class that inherits from your base gui widget such as QMainWindow. This object will then contain a member ui that is your view object you just generated.

here is an example from a tutorial

UPDATE 2013: Here is a more recent tutorial(s) on PyQt and MVC Model PyQt MVC Tutorial Series

import sys
from PyQt4 import QtCore, QtGui
from edytor import Ui_notepad

class StartQT4(QtGui.QMainWindow):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        self.ui = Ui_notepad()
        self.ui.setupUi(self)


if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    myapp = StartQT4()
    myapp.show()
    sys.exit(app.exec_())

The key point in the above example is the controller contains the ui and doesn't inherit it directly. The controller will be responsible for managing signal slots connections for your gui and providing an interface to you data model.

To describe the model part we need an example, lets assume your project is to create a movie collection database. The model would include the internal objects that represent individual movies, along with objects that represent lists of movies. You control would take the data entered from the view and catch the signals, then validate them before asking the model to update itself. That part is crucial, the controller shouldn't directly access the model if at all possible, it should ask the model to access itself.

Here is a small example of this interaction(untested, may be some typos):

class Movie():
    def __init__(self,title=None,year=None,genre=None):
        self.title=title
        self.year=year
        self.genre=genre
    def update(self,title=None,year=None,genre=None):
        self.title=title
        self.year=year
        self.genre=genre
    def to_xml(self,title=None,date=None,genre=None):
        pass #not implementing this for an example!

#when the controller tries to update it should use update function
movie1.update("Manos Hands Of Fate",1966,"Awesome")
#don't set by direct access, your controller shouldn't get that deep
movie1.title="Bad Idea" #do not want!

It is also important in MVC to centralize access, say the user can change the title by double clicking it on the screen, or by click edit next to the title field, both of those interfaces should end up using the same method for the change. And by this I don't mean each one calls movie.update_title(title). I mean that both signals should use the same method in the controller.

Try as much as possible to make all relationships between the View and the controller many to 1. Meaning, that is you have 5 ways to change something in the gui, have 1 method in the controller to handle this. If the slots aren't all compatible than create methods for each of the methods that then call one single method. If you solve the problem 5 times for 5 view styles then there really isn't and reason to separate the view from the control. Also since you now have only one way to do something in the controller you ahve a nice 1 to 1 relationship between control and model.

As far as having your model completely separate from Qt, that isn't really necessary and may actually make life harder for you. Using things like QStrings in you model can be convenient, and if in another application you don't want the overhead of a Gui but want the models just import QtCore only. Hopefully this helps!

这篇关于PyQt 和 MVC 模式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆