Back to Home

Implementing Model-View-Presenter in Qt

qt · mvp

Implementing Model-View-Presenter in Qt

    When designing the architecture of one project, he settled on the MVP pattern - he bribed the ability to easily change ui, as well as the ease of coverage with tests. All MVP implementation examples that I found on the network were in C #. When implementing on Qt, a couple of unobvious moments arose, the solution of which was successfully found. Information gathered below.

    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]:

    image

    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:

    image

    From here is a class diagram:

    image

    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.
    1. 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).
    2. 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.
    1. MVP implementation
    2. Added ability to create multiple views
    3. 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


    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

    Read Next