How to architect a Qt/C++ Application
-
Hi guys,
I've previously posted here regarding the series "Crash course in Qt for C++ developers" and have this week released the 7th part in the series. This part covers "how to organise and structure a Qt Application". Hope you like it!https://www.cleanqt.io/blog/crash-course-in-qt-for-c%2B%2B-developers,-part-7
I would be very happy if you had any feedback.
Cheers,
Alex -
Hi,
While it's a good idea to separate the GUI from the processing parts, you can also build a library of your GUI elements so you can also test them and re-use them if you have several applications in your projects.
-
If I may complain:
-
If you're taking ownership of the model, then don't hold the reference to the object in a
QPointer
, use eitherQScopedPointer
or a raw pointer. The former is for when you don't possess ownership. -
I'd not put a controller inside a library. The controller has to know about the view and the model. As such it makes little sense hiding it behind a library interface. I'd put the controller in the application drop any unnecessary abstraction(s) and keep the models and (possibly) the reusable UI components in the library.
@SGaist said in How to architect a Qt/C++ Application:
While it's a good idea to separate the GUI from the processing parts, you can also build a library of your GUI elements so you can also test them and re-use them if you have several applications in your projects.
+100
-
-
Hi,
Thanks for your comment! Agreed, the GUI components could indeed reside in a separate library so that they can be easily reused for multiple applications. Though similar idea could be said about the back-end library: it could be further decoupled to better serve multiple applications, as each application most likely only require a subset of the logic.The goal of the post was to not cover all use cases, but the focus was on "one" application presented using two different technologies (front-ends). The post is more of an introduction to architecture, as I'm sure additional separations will be required when the application grows (or when multiple applications are created using the same back-end). That said, I can see why this could be valuable to mention in order to further scale the application. I'll add a comment or two regarding this to the post. Thanks!
Thanks for the feedback!
-
I agree, conceptually what I've implemented is incorrect, so I'll change and update it. Thanks!
-
For this architecture, the Controller doesn't know about the view; only about the model. As mentioned in the post "the controllers in this design are different from the traditional definition (i.e. as defined in Smalltalk). The controllers here can be considered routers that receive user interactions but also manage the flow of the application by forwarding calls and signals to the relevant model(s) and other controller(s)". See the dependency diagram shown in the post for clarification.
That said, I believe further separation can be done by decoupling the controllers from the backend into a separate library, but IMHO the front-end should be very thin and not bundle upped with controllers.
In addition, as I mentioned in the post, there are many different ways to shape the architecture of a Qt application. The solution presented in it is only one of many, and it's most likely not a perfect fit for all domains. Your suggestion sounds a bit like Apple's approach to MVC which I'm sure also works great! See: https://developer.apple.com/library/archive/documentation/General/Conceptual/DevPedia-CocoaCore/MVC.html
Cheers,
Alex -
-
@AlexFagrell said in How to architect a Qt/C++ Application:
For this architecture, the Controller doesn't know about the view; only about the model. As mentioned in the post "the controllers in this design are different from the traditional definition (i.e. as defined in Smalltalk). The controllers here can be considered routers that receive user interactions but also manage the flow of the application by forwarding calls and signals to the relevant model(s) and other controller(s)". See the dependency diagram shown in the post for clarification.
I did see the diagram, it does look like the classical triangle you'd expect in MVC. I haven't looked at the actual code to comment further, though, so it's something I suppose I should do.
As a side comment you have this:
Qt's main event loop is entered by running the exec() member function on an instance of a QCoreApplication, a QGuiApplication or a QApplication.
in part one of your series, which is incorrect (and you should fix).
QCoreApplication::exec
is a static function and as such is not run on any instance. I've been complaining about this for some time - this misconception is spread through the docs' examples/snippets so people are left with the impressionexec
is a method, it's not. I have always thought that it's much better to be explicit about it (especially in the docs) and be written as:return QApplication::exec();
Your suggestion sounds a bit like Apple's approach to MVC which I'm sure also works great!
Well, that's the "classical" understanding of what a controller is. In Qt's examples you most often have only a model-view structure, where the view acts as the controller.
-
@kshegunov Thanks again for your feedback, appreciate it! I'll rephrase it so that it's clear that it's a static member function and update the code accordingly.
Regarding the controller, I believe there are so many different MVCs and so many variations of the controller and perspectives that it has effectively no 'classical' meaning. Another example is the one shown on the wiki https://en.wikipedia.org/wiki/Model–view–controller which doesn't depend on the view.
The model-view structure works great for directly presenting data, e.g. in a list/table/tree. However, IMO less so for the overall architecture/design of the application.
Cheers,
Alex -
The controller concept is not specific to the MVC. MVC uses one of its incarnation.
You can have a controller class that does the abstraction and handling of the lower level bits of you application while your GUI connects directly to it happily ignoring the gory details. No model required.