PyQt и MVC-шаблон

Пожалуйста, помогите мне с конструированием MVC-шаблона с PyQt. Я хочу разделить все программы на 3 части:

  • некоторый класс, который абстрагируется от всех классов Qt (модели)
  • некоторый класс, который предоставляет данные от модели до qt-app (controller)
  • Qt-приложение с определенным методом SignalsToSlots, которые соединяют сигналы с контроллером.

Оптимально ли это и какая схема используется в разработке PyQt?

P.S.: Извините за мой английский =)

Ответ 1

Одна из первых вещей, которую вы должны сделать, это использовать конструктор Qt4 для разработки своего gui и использовать pyuic4 для создания вашего графического интерфейса python. Это будет ваше мнение, вы НИКОГДА не отредактируете эти файлы python вручную. Всегда вносите изменения с помощью конструктора, это гарантирует, что ваш вид отделен от вашей модели и управления.

Для элемента управления создайте центральный класс, который наследуется от вашего базового виджета gui, такого как QMainWindow. Этот объект будет содержать член ui, который вы только что создали.

вот пример из учебника

UPDATE 2013: Вот более свежие учения по PyQt и MVC Model Учебная серия PyQt MVC

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 (название). Я имею в виду, что оба сигнала должны использовать один и тот же метод в контроллере.

Попробуйте как можно больше, чтобы все отношения между View и контроллером были много с 1. Значение, то есть у вас есть 5 способов изменить что-то в gui, у вас есть 1 метод в контроллере. Если слоты не все совместимы, чем создавать методы для каждого из методов, которые затем вызывают один единственный метод. Если вы решите проблему 5 раз для 5 стилей представления, то действительно нет и причины отделить представление от элемента управления. Кроме того, поскольку теперь у вас есть только один способ сделать что-то в контроллере, у вас есть приятная связь 1:1 между элементом управления и моделью.

Что касается того, что ваша модель полностью отделена от Qt, это на самом деле не обязательно и может на самом деле сделать жизнь сложнее для вас. Использование таких вещей, как QStrings в вашей модели, может быть удобным, и если в другом приложении вы не хотите накладных расходов на Gui, но хотите, чтобы модели просто импортировали только QtCore. Надеюсь, это поможет!

Ответ 2

Да, PyQt использует концепцию Model/View (официально без части "Контроллер" ), но может быть у вас несколько искаженное изображение, что это значит в PyQt.

Есть две части:

  • Модели, подклассы из соответствующих классов абстрактных моделей PyQt (QAbstractItemModel, QAbstractTableModel, QAbstractListModel и т.д.). Эти модели могут напрямую связываться с вашими источниками данных (файлы, базы данных) или проксировать ваши собственные PyQt-агностические модели, которые были написаны ранее.
  • Представления, которые реализованы в библиотеке Qt и часто не требуют каких-либо изменений (примеры: QTreeView, QTableView и другие). Даже некоторые более простые элементы управления, такие как QComboBox, могут выступать в качестве представления для модели PyQt.

Все остальные части вашего приложения, которые реагируют на сигналы и т.д., могут считаться "контроллером".

PyQt также предоставляет набор предопределенных "универсальных" моделей, которые могут быть подклассифицированы или использованы напрямую, если вам нужна только простая функциональность от модели, например QStringListModel, QStandardItemModel и т.д. И есть также модели, которые могут говорить к базам данных, например QSqlTableModel.

Ответ 3

Здесь ссылка на официальное и подробное руководство по тому, как архитектура Qt предлагает проект Model-View для приложения

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

В Qt вид и контроллер объединены, поэтому приложение может быть спроектировано с использованием Framework Model-View.

Модель связывается с источником данных, обеспечивая интерфейс для других компонентов в архитектуре. Характер связь зависит от типа источника данных и способа модель реализована. Вид получает модельные индексы от модели; это ссылки на элементы данных. Поставив модельные индексы в модель, представление может извлекать элементы данных из источника данных. В стандартных представлениях делегат отображает элементы данных. Когда элемент редактируется, делегат связывается с моделью напрямую, используя модельные индексы.

...

Модели, представления и делегаты общаются друг с другом с помощью сигналов и слотов