I am writing a Qt application in C++ that executes a long-running task and displays updates and final results. The UI is of barely-past-tutorial-size complexity with nested, partly custom, QWidgets. The task is executed by an object on a different QThread that has no other dependencies and is constructed in main() along with my MainWindow.
The specific thing I want to do is hook up the "update" and "finished" signals of the executor to the slots of the displaying widget in my UI. To do that, I need references to that UI widget and the executor in one place, but can't think of a satisfying way to distribute references/pointers in my application.
Things I've considered that didn't get me anywhere:
Passing the reference to the executor through the UI Widget hierarchy. I use Qt Designer which generates the whole UI setup code including calls to Widget constructors - so I can not pass that reference as constructor parameters because Qt Designer doesn't pass them. I would have to manually pass the references down after the fact with setters and connect the signals then, which strikes me as Very Ugly®.
Relaying signals through the top window, so every component would only have to connect upwards in the hierarchy, not sideways. The Executor would signal to the MainWindow, the DisplayWidget would listen to the MainWindow. This does not work, because I want to call connect() inside my DisplayWidget's constructor, which in turn is called from the MainWindow's constructor - so the MainWindow I'm connect()'ing to isn't done constructing yet.
Using a global ApplicationStructure object that holds references to my main application components and passes them to anyone who asks. We all know that the mere thought of this requires that I must be burned at the stake.
Dependency Injection. I have no experience with DI in C++. Would that be the way to go? Is there a framework someone can recommend that works well with Qt?
I'm Doing It Wrong™. Maybe I am approaching this completely the wrong way and need a more profound nudge.
Any comments or hints are appreciated.
My problem in (pseudo)code:
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
Executor e;
MainWindow m(&e);
m.show();
return a.exec();
};
// Runs on a different QThread.
class Executor {
Q_OBJECT
public:
void run() {
// very long noise.
emit done();
}
signals:
void done();
};
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(Executor* e, QWidget *parent = 0): e(e) {
ui->setupUi(this);
e->moveToThread(&workerThread);
};
~MainWindow();
private:
Ui::MainWindow *ui; // Inside here is a DisplayWidget.
Executor* e;
QThread workerThread;
};
class DisplayWidget : public QWidget
{
Q_OBJECT
public:
// Can not change parameters, call is generated.
DisplayWidget(QWidget *parent = 0) {
ui->setupUi(this);
// Right here, the pointer e: How do I get it here?
Executor* e;
connect(e, &Executor::done, this, &DisplayWidget::update);
};
~DisplayWidget();
public slots:
void update();
private:
Ui::DisplayWidget *ui;
};