Implemented as it seems to me an interface class for multithreaded objects. Everything works, except this line, when the window is closed.
connect(_controller, &IClass::finished, this, [] { qDebug() << "finished"; });
Controller::finished signal not emitted when the object is deleted (when the window is closed)?Private Controller?IClass?code example:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QDebug>
#include <QMainWindow>
#include <QThread>
class Worker1;
class Worker2;
class IClass : public QObject{
Q_OBJECT
protected:
IClass(QObject *parent = nullptr) : QObject(parent) { }
public:
enum class Types { Worker1, Worker2, };
static IClass* CreateInstance(Types t, QObject *parent = nullptr);
signals:
void started();
void finished();
public slots:
virtual void f1() = 0;
virtual void f2(int i) = 0;
virtual void f3(int x, double y) = 0;
virtual void start() = 0;
virtual void stop() = 0;
};
class PrivateController : public QObject {
Q_OBJECT
IClass *_w;
public:
PrivateController(IClass *c, QObject *parent = nullptr) : QObject(parent), _w(c) {
connect(this, &PrivateController::f1, _w, &IClass::f1);
connect(this, &PrivateController::f2, _w, &IClass::f2);
connect(this, &PrivateController::f3, _w, &IClass::f3);
connect(this, &PrivateController::stop, _w, &IClass::stop);
}
~PrivateController() override;
void callF1() { emit f1(); }
void callF2(int i) { emit f2(i); }
void callF3(int x, double y) { emit f3(x, y); }
void callStop() { emit stop(); }
signals:
void f1();
void f2(int i);
void f3(int x, double y);
void stop();
};
class Controller : public IClass {
Q_OBJECT
public:
Controller(IClass::Types t, QObject *parent = nullptr)
: IClass(parent), _w(CreateInstance(t)), _signals(_w) {
connect(_w, &IClass::started, this, &IClass::started);
connect(_w, &IClass::finished, this, &IClass::finished);
}
~Controller() override;
public slots:
void f1() override { _signals.f1(); }
void f2(int i) override { _signals.f2(i); }
void f3(int x, double y) override { _signals.f3(x, y); }
void start() override {
QThread *th = new QThread;
_w->moveToThread(th);
connect(th, &QThread::started, _w, &IClass::start);
connect(_w, &IClass::finished, th, &QThread::quit);
connect(_w, &IClass::finished, th, &QThread::deleteLater);
connect(_w, &IClass::finished, _w, &IClass::deleteLater);
th->start();
qDebug() << "Controller::start";
}
void stop() override {
_signals.stop();
qDebug() << "Controller::stop";
}
protected:
IClass *_w;
PrivateController _signals;
};
class Worker1 : public IClass {
Q_OBJECT
public:
Worker1(QObject *parent = nullptr)
: IClass(parent) {
// some code
}
public slots:
void f1() override {
qDebug() << "Worker1::f1";
}
void f2(int i) override {
qDebug() << "Worker1::f2" << i;
}
void f3(int x, double y) override {
qDebug() << "Worker1::f3" << x << y;
}
void start() override {
emit started();
qDebug() << "Worker1::start";
}
void stop() override {
emit finished();
qDebug() << "Worker1::stop";
}
protected:
// some code
};
class Worker2 : public IClass {
Q_OBJECT
public:
Worker2(QObject *parent = nullptr)
: IClass(parent) {
// some code
}
public slots:
void f1() override {
qDebug() << "Worker2::f1";
}
void f2(int i) override {
qDebug() << "Worker2::f2" << i;
}
void f3(int x, double y) override {
qDebug() << "Worker2::f3" << x << y;
}
void start() override {
emit started();
qDebug() << "Worker2::start";
}
void stop() override {
emit finished();
qDebug() << "Worker2::stop";
}
protected:
// some code
};
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
IClass *_controller;
};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow),
_controller(new Controller(IClass::Types::Worker2, this))
{
ui->setupUi(this);
connect(_controller, &IClass::started, this, [] { qDebug() << "started"; });
connect(_controller, &IClass::finished, this, [] { qDebug() << "finished"; });
_controller->start();
_controller->f1();
_controller->f2(2);
_controller->f3(3, 4.4);
// _controller->stop();
}
MainWindow::~MainWindow() { delete ui; }
PrivateController::~PrivateController() { qDebug() << "~PrivateController()"; }
IClass *IClass::CreateInstance(IClass::Types t, QObject *parent) {
switch(t) {
case Types::Worker1: { return new Worker1(parent); }
case Types::Worker2: { return new Worker2(parent); }
}
}
Controller::~Controller() { _signals.callStop(); }
OUTPUT:
Controller::start
Worker2::start
Worker2::f1
Worker2::f2 2
Worker2::f3 3 4.4
started
~PrivateController()
Worker2::stop
Don't emited finished.
About question #2: try this edit to your main:
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
int r = a.exec();
qDebug() << "event loop gone ...";
return r;
}
Check your output, now. As you can see, when the finished signal is emitted, your main thread hasn't an event loop anymore, so the signal won't be caught (because it's coming from the other thread).
To prove it further, add a push button to the window and have a clicked slot like this:
void MainWindow::on_pushButton_clicked()
{
_controller->stop();
qApp->processEvents();
qApp->exit();
}
This way you exit the app, but only after all queued events got processed (i.e. the queued signal gets delivered ...).
About everything else you ask, frankly: it's seems quite broad even for a bounty question. Anyway, hope I have helped a bit.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With