【发布时间】:2010-12-12 05:47:05
【问题描述】:
我正在尝试使用 PyQt 设计 MVC 模式。 我想将所有程序分成 3 个部分:
- 从所有 Qt 类(模型)中抽象出来的类
- 将数据从模型提供给 Qt 应用程序(控制器)的类
- Qt 应用程序本身具有定义的方法
SignalsToSlots,将信号与控制器连接。
这是最优的吗?在 PyQt 开发中推荐使用什么方案?
【问题讨论】:
我正在尝试使用 PyQt 设计 MVC 模式。 我想将所有程序分成 3 个部分:
SignalsToSlots,将信号与控制器连接。这是最优的吗?在 PyQt 开发中推荐使用什么方案?
【问题讨论】:
您应该做的第一件事是使用 Qt4 设计器来设计您的 gui 并使用 pyuic4 来生成您的 python GUI。这将是你的观点,你永远不要手动编辑这些 python 文件。始终使用设计器进行更改,这样可以确保您的视图与您的模型和控件分开。
对于控制元素,创建一个继承自基本 gui 小部件(例如 QMainWindow)的中心类。然后,该对象将包含一个成员 ui,它是您刚刚生成的视图对象。
这是来自a tutorial的示例
2013 年更新:这是有关 PyQt 和 MVC 模型的更新教程 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_())
上面例子中的关键点是控制器包含了 ui 并且不直接继承它。控制器将负责管理您的 gui 的信号槽连接并为您的数据模型提供接口。
为了描述模型部分,我们需要一个示例,假设您的项目是创建一个电影集合数据库。该模型将包括表示单个电影的内部对象,以及表示电影列表的对象。您可以控制从视图中输入的数据并捕获信号,然后在要求模型自我更新之前验证它们。这部分很关键,如果可能的话,控制器不应该直接访问模型,它应该要求模型访问自己。
这里是这个交互的一个小例子(未经测试,可能有一些错别字):
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!
在 MVC 中集中访问也很重要,比如用户可以通过在屏幕上双击来更改标题,或者通过单击标题字段旁边的编辑,这两个界面都应该最终使用相同的方法进行更改。我并不是说每个人都调用movie.update_title(title)。我的意思是两个信号都应该在控制器中使用相同的方法。
尽量让 View 和控制器之间的所有关系多为 1。意思是,你有 5 种方法可以在 gui 中更改某些内容,控制器中有 1 种方法来处理这个问题。如果插槽不是全部兼容,则为每个方法创建方法,然后调用一个方法。如果你为 5 种视图样式解决了 5 次问题,那么确实没有理由将视图与控件分开。此外,由于您现在只有一种方法可以在控制器中执行某项操作,因此您可以在控件和模型之间建立良好的 1 对 1 关系。
就让您的模型与 Qt 完全分离而言,这并不是真正必要的,而且实际上可能会让您的生活更加艰难。在你的模型中使用 QStrings 之类的东西会很方便,如果在另一个应用程序中你不想要 Gui 的开销但希望模型只导入 QtCore。希望这会有所帮助!
【讨论】:
don't set by direct access, your controller shouldn't get that deep: 为什么不提self._title=title; self._year=year; ...的可能性呢?
是的,PyQt 使用模型/视图概念(官方没有“控制器”部分),但您可能对 PyQt 中的含义有些扭曲。
有两个部分:
QAbstractItemModel、QAbstractTableModel、QAbstractListModel 等)子类化。这些模型可以直接与您的数据源(文件、数据库)对话,或者代理您自己之前编写的与 PyQt 无关的模型。QTreeView、QTableView 等)。即使是一些更简单的控件,例如QComboBox,也可以充当 PyQt 模型的视图。应用程序的所有其他部分,对信号等做出反应的部分都可以被视为“控制器”。
PyQt 还提供了一组预定义的“通用”模型,如果您只需要模型中的简单功能,可以将其子类化或直接使用,例如 QStringListModel、QStandardItemModel 等。还有一些模型可以说话直接到数据库,比如QSqlTableModel。
【讨论】:
QAbstractItemModel 在您的代码中子类化与QStandardItemModel 或QStringListModel)。我会说 Qt 视图不是“纯”视图,它们是视图和控制器的混合体。另外我想指出,这种纯度/术语讨论与实际的软件开发完全无关,是您偏好的抽象级别问题;)
这是关于 Qt 架构如何为应用程序提供模型视图设计的官方详细指南的链接
http://doc.qt.io/qt-5/model-view-programming.html
在 Qt 中,视图和控制器是结合在一起的,因此可以使用 Model-View 框架设计应用程序。
模型与数据源通信,提供接口 对于架构中的其他组件。的性质 通信取决于数据源的类型,以及 模型实现。视图从模型中获取模型索引; 这些是对数据项的引用。通过提供模型索引 在模型中,视图可以从数据源中检索数据项。 在标准视图中,委托呈现数据项。当一个项目 被编辑,委托直接使用与模型通信 模型索引。
...
模型、视图和委托使用信号和槽相互通信
【讨论】: