Creating custom slots and signals
-
Hi
I have a worker thread and a main GUI. The worker thread reads values every 3 seconds.
I want to emit that value to the main GUI every 3 seconds. How do I do that?
I tried reading the documentation from qt5 but this is as far as I got:
cpu_thread.h
#ifndef CPU_THREAD_H #define CPU_THREAD_H #include <QThread> class cpu_thread : public QThread { Q_OBJECT public: cpu_thread(); void run(); public slots: void setValue(int value); signals: void valueChanged(int value); }; #endif // CPU_THREAD_H
cpu_thread.cpp
#include "cpu_thread.h" #include <QDebug> #include <QProcess> #include <QTest> cpu_thread::cpu_thread() { } void cpu_thread::run() { while (true) { QThread *thread = new QThread; QProcess *process = new QProcess; process->moveToThread(thread); process->start("cat /proc/loadavg"); process->waitForFinished(-1); QString stdout = process->readAllStandardOutput().trimmed(); stdout.truncate(4); qDebug() << stdout; QTest::qWait(3000); } } void cpu_thread::setValue(int value) { emit valueChanged(value); }
Now the main gui which is supposed to capture the value and update the gui looks like this:
#include "ui_mainwindow.h" #include <QProcess> #include <QDebug> #include <QThread> #include <cpu_thread.h> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); cpu_thread *my_thread = new cpu_thread; my_thread->start(); cores = getCpuCores(); } MainWindow::~MainWindow() { delete ui; } void MainWindow::on_actionExit_triggered() { qApp->exit(); } void MainWindow::mousePressEvent(QMouseEvent *event) { m_nMouseClick_X_Coordinate = event->x(); m_nMouseClick_Y_Coordinate = event->y(); } void MainWindow::mouseMoveEvent(QMouseEvent *event) { move(event->globalX()-m_nMouseClick_X_Coordinate,event->globalY()-m_nMouseClick_Y_Coordinate); } int MainWindow::getCpuCores() { QProcess *process = new QProcess; process->start("nproc"); process->waitForFinished(-1); QString stdout = process->readAllStandardOutput().trimmed(); QString stderr = process->readAllStandardError().trimmed(); int cores = stdout.toInt(); return cores/2; } void MainWindow::test() { QThread *thread = new QThread; QProcess *process = new QProcess; process->moveToThread(thread); process->start("cat /proc/loadavg"); process->waitForFinished(-1); QString stdout = process->readAllStandardOutput().trimmed(); qDebug() << stdout; } void MainWindow::updateCpu(QString value) { ui->lcdNumber->display(value); }```
-
Hi
I have a worker thread and a main GUI. The worker thread reads values every 3 seconds.
I want to emit that value to the main GUI every 3 seconds. How do I do that?
I tried reading the documentation from qt5 but this is as far as I got:
cpu_thread.h
#ifndef CPU_THREAD_H #define CPU_THREAD_H #include <QThread> class cpu_thread : public QThread { Q_OBJECT public: cpu_thread(); void run(); public slots: void setValue(int value); signals: void valueChanged(int value); }; #endif // CPU_THREAD_H
cpu_thread.cpp
#include "cpu_thread.h" #include <QDebug> #include <QProcess> #include <QTest> cpu_thread::cpu_thread() { } void cpu_thread::run() { while (true) { QThread *thread = new QThread; QProcess *process = new QProcess; process->moveToThread(thread); process->start("cat /proc/loadavg"); process->waitForFinished(-1); QString stdout = process->readAllStandardOutput().trimmed(); stdout.truncate(4); qDebug() << stdout; QTest::qWait(3000); } } void cpu_thread::setValue(int value) { emit valueChanged(value); }
Now the main gui which is supposed to capture the value and update the gui looks like this:
#include "ui_mainwindow.h" #include <QProcess> #include <QDebug> #include <QThread> #include <cpu_thread.h> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); cpu_thread *my_thread = new cpu_thread; my_thread->start(); cores = getCpuCores(); } MainWindow::~MainWindow() { delete ui; } void MainWindow::on_actionExit_triggered() { qApp->exit(); } void MainWindow::mousePressEvent(QMouseEvent *event) { m_nMouseClick_X_Coordinate = event->x(); m_nMouseClick_Y_Coordinate = event->y(); } void MainWindow::mouseMoveEvent(QMouseEvent *event) { move(event->globalX()-m_nMouseClick_X_Coordinate,event->globalY()-m_nMouseClick_Y_Coordinate); } int MainWindow::getCpuCores() { QProcess *process = new QProcess; process->start("nproc"); process->waitForFinished(-1); QString stdout = process->readAllStandardOutput().trimmed(); QString stderr = process->readAllStandardError().trimmed(); int cores = stdout.toInt(); return cores/2; } void MainWindow::test() { QThread *thread = new QThread; QProcess *process = new QProcess; process->moveToThread(thread); process->start("cat /proc/loadavg"); process->waitForFinished(-1); QString stdout = process->readAllStandardOutput().trimmed(); qDebug() << stdout; } void MainWindow::updateCpu(QString value) { ui->lcdNumber->display(value); }```
@Fuchsiaff said in Creating custom slots and signals:
cpu_thread *my_thread = new cpu_thread; connect(my_therad, &cpu_thread::valueChanged, this, &MainWindow::someSlotYouCreateInMainWindow); my_thread->start()
That should do it on UI side. In your thread, you need to emit the value, that would probably look like:
qDebug() << stdout; // BTW that's a HORRIBLE variable name! emit valueChanged(stdout.toInt()); QTest::qWait(3000);
But, and that is a BIG but - your code is overdoing it massively.
You don't need a thread. QProcess already runs in a separate process - it won't block your UI at all! So you can simplify all this like so:
- remove whole cpu_thread class
- in MainWindow do this:
QTimer *timer = new QTimer(this); timer->setInterval(3000); timer->setSingleShot(false); // Using a lambda, but you can (should) create your own slot for this, of course connect(timer, &QTimer::timeout, this, [this] { QProcess *process = new QProcess(this); process->start("cat /proc/loadavg"); connect(process, &QProcess::finished, this, &MainWindow::someSlot); }); // Your slot: void MainWindow::someSlot() { QProcess *process = qobject_cast<QProcess *>(sender()); ui->lcdNumber->display(process->readAllStandardOutput()); process->deleteLater(); }
Brain to terminal, not tested of course. But it should give you a general idea.
-
Anyway, after using code suggested by sierdzo,
mainwindow.cpp
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); QTimer *timer = new QTimer(this); timer->setInterval(3000); timer->setSingleShot(false); // Using a lambda, but you can (should) create your own slot for this, of course QObject::connect(timer, &QTimer::timeout, this, [this] { QProcess *process = new QProcess(this); process->start("cat /proc/loadavg"); QObject::connect(process, &QProcess::finished, this, &MainWindow::updateCpu); }); cores = getCpuCores(); } void MainWindow::updateCpu(int exitCode, QProcess::ExitStatus exitStatus) { QProcess *process = qobject_cast<QProcess *>(sender()); QString result = process->readAllStandardOutput().trimmed(); result.truncate(4); ui->lcdNumber->display(result); process->deleteLater(); }
mainwindow.h
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMouseEvent> #include <QMainWindow> #include <QProcess> namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = nullptr); int getCpuCores(); void updateCpu(int exitCode, QProcess::ExitStatus exitStatus); void updateRAM(QString value); void updateNetwork(QString value); void updateFanSpeed(QString value); int cores; ~MainWindow(); private slots: void on_actionExit_triggered(); private: void mousePressEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event); int m_nMouseClick_X_Coordinate; int m_nMouseClick_Y_Coordinate; Ui::MainWindow *ui; bool isMouseDown = false; }; #endif // MAINWINDOW_H
Qtcreator shows me this:
No matching function call for call to "connect"
-
What is the exact error ?
-
/home/bot/Hardware_mon/mainwindow.cpp:19: error: no matching function for call to ‘MainWindow::connect(QProcess*&, <unresolved overloaded function type>, MainWindow*, void (MainWindow::*)(int, QProcess::ExitStatus))’ QObject::connect(process, &QProcess::finished, this, &MainWindow::updateCpu); ^
-
The documentation has the proper code for this connect.
-
So something like this?
connect(process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), [=](int exitCode, QProcess::ExitStatus exitStatus){ QProcess *process = new QProcess(this); process->start("cat /proc/loadavg"); QObject::connect(process, &QProcess::finished, this, &MainWindow::updateCpu); });
that connect looks even more confusing, i'm even more lost now
-
So something like this?
connect(process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), [=](int exitCode, QProcess::ExitStatus exitStatus){ QProcess *process = new QProcess(this); process->start("cat /proc/loadavg"); QObject::connect(process, &QProcess::finished, this, &MainWindow::updateCpu); });
that connect looks even more confusing, i'm even more lost now
Hi @Fuchsiaff: Then try this:
QByteArray avg; QFile f("/proc/loadavg"); if (f.open(QIODevice::ReadOnly)) { avg = f.readAll(); f.close(); } // avg now contains the content of /proc/loadavg
-
QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished)
reads as: use the overloaded version of finished having the matching signature:
QProcess::finished(int, QProcess::ExitStatus)
-
I got it to compile with this code
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); QTimer *timer = new QTimer(this); timer->setInterval(3000); timer->setSingleShot(false); // Using a lambda, but you can (should) create your own slot for this, of course QObject::connect(timer, &QTimer::timeout, this, [this] { QProcess *process = new QProcess(this); process->start("cat /proc/loadavg"); qDebug() << "hi"; QObject::connect(process, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(updateCpu(int, QProcess::ExitStatus))); }); cores = getCpuCores(); }
But now, looking at the application output section, the string "hi" isn't printed so i'm quessing the timer never reached the timeout signal, but why?
-
From the code you posted, you don't start
timer
.