PDA

View Full Version : General application structure with Qt



CoderMan
6th August 2011, 22:07
Yo!

I have a couple of years of experience in maintaining Qt programs, but have never created a non-trivial application from scratch. Now I suddenly find myself confused by requirements for the topmost architecture. Once I get up to speed I'm sure I'll be able to add stuff to the software without problems, but how do I structure the entire thing, starting right from main.cpp?

This exact question was asked in this (http://www.qtcentre.org/threads/38433-Application-architecture) thread, but the answers are not satisfactory. I do not want to use the full, heavy model/view approach, with all the Qt classes that have "Model", "Delegate" or "View" in the name. Yet obviously I want some kind of wall of separation between UI and program logic.

Currently main() instantiates QApplication, QMainWindow and my own general manager class. The mainwindow holds some common controls directly as member variables and will hold instances of sub-views with their own UI components. The manager opens configuration files, handles communication protocols and generally makes things happen. Anything in the UI part of the program will be subclassed from QWidget while anything in the logic part will inherit QObject.

Thus, the questions are --

Where should I instantiate the mainwindow and manager classes?
Does either of the instances hold a pointer to the other?
How do I implement an interface between them -- where will the connect() commands go?

Pray grant succour, grand architectural design is quite vexing.

SixDegrees
6th August 2011, 22:35
There are an infinite number of ways to do this. Without knowing more about your application, it's impossible to narrow things down much. However, a common approach that works well for many applications is to simply encapsulate your manager class within your mainwindow class. This makes establishing connections and other communications between the two parts simple, and keeps them separate at the same time. Just be careful not to intermingle UI code and computational, model or manager code to the point where they're difficult to separate. Sometimes it is useful to create small "bridge" classes that add a further abstraction layer between these components; other times, this is overkill.

CoderMan
7th August 2011, 17:57
However, a common approach that works well for many applications is to simply encapsulate your manager class within your mainwindow class.

Well, having the mainwindow instance simply keep the sole instance of the manager class as a member variable would certainly work, but somehow I see this as an inversion of authority... the manager is supposed to be the king in the application. :)

QMainWindow does not have to be instantiated in main() does it? That is, I can make a class that merely owns both the manager and the main window?

mattc
7th August 2011, 20:01
This is very application specific, so I can just share my own experience with you. This is from a network application interacting with a server:

I have two top level classes:

// the view
MyMainWindow: public QMainWindow

// the controller (+ lightweight model)
MyApplication: public QObject

with the following responsibilities:

MyMainWindow:

creates widgets
forwards almost any request to MyApplicaiton (through signals)

MyApplication:

creates and shows MyMainWindow
handles signals from MyMainWindow
delegates tasks to other top level classes (singletons or private members)

and my main() looks like this:


int main(int argc, char** argv)
{
QApplication app(argc, argv);

MyApplication application;
application.create();

return app.exec();
}

dave2k
9th August 2011, 14:35
Take a look at Pure MVC framework. If you dig about you will find a couple of c++ versions*of this framework. I am using a c++ version (I had to modify it a bit) For my Qt project. It simplifies development of large apps so much, I couldn't imagine developing without it!

GTDev
31st January 2019, 14:48
Since the introduction of QML, you can save vast amount of development time by only stepping into C++ for certain tasks that require it.
We've prepared a comprehensive guide how to create and structure QML-driven apps, check it out here: https://v-play.net/apps/avoid-cpp-models-qt

Cheers,
GTDev

d_stranz
31st January 2019, 19:23
Resurrecting long-dead posts with your advertising spam will get you bounced off the forum.

anda_skoa
3rd February 2019, 10:08
Since the introduction of QML, you can save vast amount of development time by only stepping into C++ for certain tasks that require it.

This is true to a certain extent, it depends on definitions of "require it".

Inexperienced developers often interpret it in the sense of "if performance requires it", forgetting about the much more common requirement of stability of code quality.

JavaScript is good for prototyping and demos, essentially code that needs to be written in a short time but won't have to be maintained.

Once code reaches the state of when it is expected to updated (fixed and/or new features) it becomes far more sensible to do it in C++.
There are far more tools available to analyze and check C++ code and a lot of JavaScript tooling is specific to its use in web browsers.

Even without special tools, the C++ compiler alone can prevent a lot of misery due to its far stricter handling of identifiers.
For example the following JavaScript code has a simple typo a C++ compiler would have generated an error for:


function add(param1, param2) {
var result = 0;

resut = param1 + param2;

return result;
}

console.log("add(1,2)=" + add(1, 2));

A JavaScript engine will happy accept "resut" as a new local variable, leading to the rather surprising result that "1+2" is "0".

The equivalent C++ code


#include <iostream>

int add(int param1, int param2) {
int result = 0;

resut = param1 + param2;

return result;
}

int main() {
std::cout << "add(1, 2)=" << add(1, 2) << std::endl;

return 0;
}

leads to


/tmp/test.cpp: In function ‘int add(int, int)’:
/tmp/test.cpp:6:5: error: ‘resut’ was not declared in this scope
resut = param1 + param2;
^~~~~
/tmp/test.cpp:6:5: note: suggested alternative: ‘result’
resut = param1 + param2;
^~~~~
result


Cheers,
_