📜 ⬆️ ⬇️

Implementing a Model-View-Presenter in Qt

Designing the architecture of one project, I stopped at the MVP pattern - I was bribed by the ability to easily change ui, as well as the simplicity of the test coverage. All examples of MVP implementations that I found online were in C #. When implemented on Qt, a pair of unobvious moments arose, the solution of which was successfully found. The information collected is below.

MVP history


As follows from [1] and [2], the MVP design pattern is a modification of MVC applied for the first time in IBM in the 90s of the last century when working on the object-oriented operating system Taligent. Later MVP described Mike Pottel in detail.

To see what is the difference between MVP and MVC, you can see the corresponding paragraphs [3]: MVC , MVP

MVP implementation in Qt


In general, MVP is already used implicitly in Qt, as shown in [4]:
')
image

But this implementation of MVP has several disadvantages:

The full implementation of MVP will look like this:

image

Hence the class diagram:

image

Consider each class:

At the stage of “drawing squares” everything is clear. Problems I had while trying to implement.
  1. When writing IView, you must declare signals. But for this IView must be inherited from QObject. Then, when trying to inherit View simultaneously from QWidget and IView, an error occurred. It turned out that a class cannot be inherited simultaneously from two QObject objects (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 signals as completely virtual (abstract) methods in the public section. This is quite logical, since a signal is also a function, on call of which observers are notified through their slots (see the Observer pattern).
  2. Another problem arose when linking IView signals in the Presenter class. The fact is that Presenter contains a reference to IView (a specific View is added to the Presenter at runtime, but stored as IView — polymorphism is used). But for connecting signals and slots, the static QObject::connect() method is used, which accepts only heirs from QObject as objects, and IView is not one. But we know that any our View will be it. So the problem is solved by dynamic type conversion, as shown in [6]:

    QObject   * view_obj   =   dynamic_cast < QObject *>( m_view );   //     m_view   -   IView
    QObject :: connect ( view_obj ,   SIGNAL ( okActionTriggered ()),
                      this ,   SLOT ( processOkAction ()));


It is also worth noting that when implementing IView, only a header (.h) file is needed. If an .cpp file has been 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 the interaction in the context of a real application).

A simple example of using MVP in Qt


In the archive 3 examples, this is the same application, but with additions in each example.
  1. MVP implementation
  2. Added the ability to create multiple views
  3. Full synchronization between views when data changes

All code is commented on 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 are not included in the article:

Comments are welcome any information on these issues.

Sources


  1. http://www.rsdn.ru/article/patterns/generic-mvc2.xml
  2. http://en.wikipedia.org/wiki/Model-view-presenter
  3. http://www.rsdn.ru/article/patterns/ModelViewPresenter.xml
  4. http://thesmithfam.org/blog/2009/09/27/model-view-presenter-and-qt/
  5. http://doc.trolltech.com/qq/qq15-academic.html
  6. http://developer.qt.nokia.com/forums/viewthread/284

Source: https://habr.com/ru/post/107698/


All Articles