Implementing Model-View-Presenter in Qt
MVP story
As follows from [1] and [2], the MVP design pattern is a modification of MVC, first used by IBM in the 90s of the last century when working on the object-oriented operating system Taligent. Later, MVP was described in detail by Mike Potel.
To see the difference between MVP and MVC, one can look at the corresponding paragraphs [3]: MVC , MVP
Implement MVP in Qt
In general, MVP is already used implicitly in Qt, as shown in [4]:

But such an implementation of MVP has several disadvantages:
- it is not possible to create multiple views for one representative (Presenter)
- it is impossible to use the Inversion of Control pattern described in [3] ( here ), because in this scheme, the View is generated automatically and cannot be inherited from the interface
A full MVP implementation would look like this:

From here is a class diagram:

Consider each class:
- IView - an interface class that defines the methods and signals that a particular View should implement (see Inversion of Control in [3])
- Ui :: View - a class generated by the .ui file of a Qt designer
- View is a specific view inherited from QWidget (or its descendant) and from IView. Contains GUI logic, i.e. behavior of objects (for example, their animation)
- Model - domain data model (Domain Model); contains variables, flags, table models, etc.
- Presenter - representative; implements the interaction between the model and the view. Also through it there is an interaction with the outside world, i.e. with the main application, with the server (for example, through the application services layer), etc.
At the stage of "drawing squares" everything is clear. I had problems trying to implement it.
- When writing IView, you must declare signals. But for this, IView must be inherited from QObject. Then, when trying to inherit View from QWidget and IView at the same time, an error occurred. It turned out that the class cannot be inherited from two QObject objects at the same time (even virtual inheritance did not help). How to get around this problem is shown in [5]: link . Thus, IView is not inherited from QObject and simply declares the signals as fully virtual (abstract) methods in the public section. This is quite logical, because the signal is also a function by calling which the observers are notified through their slots (see the Observer pattern).
- Another problem occurred when binding IView signals in the Presenter class. The fact is that Presenter contains a link to IView (a specific View is added to Presenter at run time, but stored as IView - polymorphism is used). But to connect signals and slots, the static method is used
QObject::connect(), which takes as objects only heirs from QObject, but IView is not. But we know that any of our View will be it. So the problem is solved by dynamic type conversion, as shown in [6]:QObject *view_obj = dynamic_cast(m_view); // где m_view - IView
QObject::connect(view_obj, SIGNAL(okActionTriggered()),
this, SLOT(processOkAction()));
It is also worth noting that when implementing IView, only the header (.h) file is needed. If a .cpp file is created for IView, it must be deleted, otherwise compilation problems may occur.
In principle, this information is enough to independently implement MVP in Qt, but I will give a simple example (only the implementation of MVP, without considering interaction in the context of a real application).
A simple example of using MVP in Qt
There are 3 examples in the archive, this is the same application, but with additions in each example.
- MVP implementation
- Added ability to create multiple views
- Full synchronization between views when data changes
All code is commented in Doxygen style, i.e. You can easily generate documentation using the Doxywizard.
Download examples here
Out of scope
Here is a list of interesting questions on the topic that were not included in the article:
- testing the modules of the resulting system
- implementation of View as libraries (using QtPlugin) in the context of MVP
- implementation of View with QtDeclarative (QML) in the context of MVP
- transferring views to Presenter through a class factory (this way you can easily change styles)
Any information on these issues is welcome in the comments.
Sources
- http://www.rsdn.ru/article/patterns/generic-mvc2.xml
- http://en.wikipedia.org/wiki/Model-view-presenter
- http://www.rsdn.ru/article/patterns/ModelViewPresenter.xml
- http://thesmithfam.org/blog/2009/09/27/model-view-presenter-and-qt/
- http://doc.trolltech.com/qq/qq15-academic.html
- http://developer.qt.nokia.com/forums/viewthread/284