【问题标题】:PyQt and MVC-patternPyQt 和 MVC 模式
【发布时间】:2010-12-12 05:47:05
【问题描述】:

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

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

这是最优的吗?在 PyQt 开发中推荐使用什么方案?

【问题讨论】:

    标签: python qt pyqt


    【解决方案1】:

    您应该做的第一件事是使用 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。希望这会有所帮助!

    【讨论】:

    • +1, don't set by direct access, your controller shouldn't get that deep: 为什么不提self._title=title; self._year=year; ...的可能性呢?
    • 为什么手动编辑视图会导致它与模型和控件分离?
    • 它不会导致它,但不这样做阻止它
    【解决方案2】:

    是的,PyQt 使用模型/视图概念(官方没有“控制器”部分),但您可能对 PyQt 中的含义有些扭曲。

    有两个部分:

    1. 模型,从适当的 PyQt 基本抽象模型类(QAbstractItemModelQAbstractTableModelQAbstractListModel 等)子类化。这些模型可以直接与您的数据源(文件、数据库)对话,或者代理您自己之前编写的与 PyQt 无关的模型。
    2. 视图,在 Qt 库中实现,通常不需要任何修改(例如:QTreeViewQTableView 等)。即使是一些更简单的控件,例如QComboBox,也可以充当 PyQt 模型的视图。

    应用程序的所有其他部分,对信号等做出反应的部分都可以被视为“控制器”。

    PyQt 还提供了一组预定义的“通用”模型,如果您只需要模型中的简单功能,可以将其子类化或直接使用,例如 QStringListModelQStandardItemModel 等。还有一些模型可以说话直接到数据库,比如QSqlTableModel

    【讨论】:

    • 请注意,Qt 中的模型/视图框架仅限于递归表(尽管视图主要支持列表、行、表和递归行(树))。如果您的数据具有不同的结构,则可以在不使用 Qt 的 ModelView 框架的 PyQt/Qt 中构建通用 MVC 应用程序。 (恕我直言,将东西强制放入 Qt 的 ModelView 并不总是最好的主意......)
    • 确实~我还是不太明白Qt的模型/视图框架w/o控制器的真正想法。
    • 它使代码复用更好。当您使用完全相同的模型类或什至具有不同视图的实例时,这是很常见的(例如,在一个对话框窗口中使用 QTreeView,在另一个对话框中使用 QComboBox)。
    • @abbot:在我看来,Qt 的模型将“成为”MVC 结构中某些控制器(通过组合或聚合)的一部分。 MVC 结构的模型不应该对 Qt 框架有任何引用。换句话说,Qt 的模型只是 UI 项的数据提供者。我是否过于简单化了它们?
    • @freitass:从这个意义上说,Qt 模型是非常普通的模型,无论它们是否是您的底层“真实”模型类的代理(想想QAbstractItemModel 在您的代码中子类化与QStandardItemModelQStringListModel)。我会说 Qt 视图不是“纯”视图,它们是视图和控制器的混合体。另外我想指出,这种纯度/术语讨论与实际的软件开发完全无关,是您偏好的抽象级别问题;)
    【解决方案3】:

    这是关于 Qt 架构如何为应用程序提供模型视图设计的官方详细指南的链接

    http://doc.qt.io/qt-5/model-view-programming.html

    在 Qt 中,视图和控制器是结合在一起的,因此可以使用 Model-View 框架设计应用程序。

    模型与数据源通信,提供接口 对于架构中的其他组件。的性质 通信取决于数据源的类型,以及 模型实现。视图从模型中获取模型索引; 这些是对数据项的引用。通过提供模型索引 在模型中,视图可以从数据源中检索数据项。 在标准视图中,委托呈现数据项。当一个项目 被编辑,委托直接使用与模型通信 模型索引。

    ...

    模型、视图和委托使用信号和槽相互通信

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-07-10
      • 2010-10-13
      • 2010-12-10
      • 2011-03-10
      • 1970-01-01
      • 2020-10-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多