main H :
`
namespace Ui {
class StrategyManageMent;
}
class StrategyManageMent : public QWidget //class MainWindow
{
Q_OBJECT
public:
explicit StrategyManageMent(QWidget *parent = nullptr);
~StrategyManageMent();
private:
Ui::StrategyManageMent *ui;
QThread *tHighAG = new QThread; //QThread *t1= new QThread;
QThread* tLowAG = new QThread;
HighAG *HighAGTh = new HighAG; //work1=HighAGTh,HighAG=Thread1
// Thread2* work2 = new Thread2;
public slots:
void receiveKlineInformation(QString symbol, OneSymbolKlineData *data);
void receiveQuoteInformation(std::shared_ptr<QuoteInfo>);
void on_addStrategy_clicked();
void on_StartStrategy_clicked();
void on_StopStrategy_clicked();
void OnTick(QString symbol, std::shared_ptr<QuoteInfo>);
signals:
void startHigh(int num); //void starting1(int num);
void startLow(int num);
void STMsendTick(std::shared_ptr<QuoteInfo>);
};
`
main cpp:
`
StrategyManageMent::StrategyManageMent(QWidget *parent) :
QWidget(parent),
ui(new Ui::StrategyManageMent)
{
ui->setupUi(this);
this->setWindowTitle("Threads");
ui->tableWidget->setHorizontalHeaderLabels(QStringList() << "Time" << "logs" << "act");
HighAGTh->moveToThread(tHighAG);
connect(this, &StrategyManageMent::startHigh, HighAGTh, &HighAG::startHighAG);
connect(ui->StartStrategy, &QPushButton::clicked, this, [=]() {
emit startHigh(1000);
tHighAG->start();
HighAGTh->AGstart = true;
connect(this, SIGNAL(STMsendTick(std::shared_ptr<QuoteInfo>)), HighAGTh, SLOT(On_Tick(std::shared_ptr<QuoteInfo>)));
//connect(HighAGTh, SIGNAL(sendTick(std::queue<QuoteInfo>)), HighAGTh, SLOT(startHighAG(std::queue<QuoteInfo>)));
});
connect(ui->StopStrategy, &QPushButton::clicked, this, [=]() {
HighAGTh->AGstart = false;
tHighAG->quit();
tHighAG->wait();
disconnect(this, SIGNAL(STMsendTick(std::shared_ptr<QuoteInfo>)), HighAGTh, SLOT(On_Tick(std::shared_ptr<QuoteInfo>)));
});
}
void StrategyManageMent::OnTick(QString, std::shared_ptr<QuoteInfo> quote)
{
// qDebug() << "StrategyManageMent::OnTick datas:" << quote->lastPrice; //datas can be printed out here.
emit STMsendTick(quote);
}
`
Thread H:
`
class HighAG : public QObject //Thread1
{
Q_OBJECT
public:
explicit HighAG (QObject* parent = nullptr);
QString m_strategy_name;
bool AGstart = false;
struct QuoteInfo* tickdata;
std::queue<QuoteInfo> tickQue;
signals:
void working(int num);
void finish(QString elapsedTime);
void sendTick(std::queue<QuoteInfo> tickQue);
public slots:
void On_Tick(std::shared_ptr<QuoteInfo>);
void startHighAG(int num); //begin
private:
};
`
Thread cpp:
`
HighAG::HighAG (QObject* parent) : QObject(parent)
{
// std::shared_ptr<QuoteInfo> tickdata(new QuoteInfo);
}
void HighAG::startHighAG(int num)
{
qDebug() << " Thread start" << " || " << QThread::currentThread();
while (AGstart) {
{
//QMutexLocker locker(&lock);
qDebug() << "Thread running ";
qDebug() << "*****Thread startHighAG::OnTick:" << this->tickQue.back().askPrice1; //shows empty queue error here.
QThread::sleep(1);
if (!AGstart) {
break;
}
}
//emit resultReady(parameter + "running......");
}
qDebug() << "Stopped " ;
// emit finish(QString::number(time.elapsed()));
}
void HighAG::On_Tick(std::shared_ptr<QuoteInfo> quote)
{
tickQue.push(*quote);
qDebug() << "startHighAG::OnTick:" << tickQue.back().askPrice1; //datas can be printed out well.
emit sendTick(tickQue);
}
`
In the On_Tick slot, it can print out different datas coming in. means On_Tick slot working.
In thread HighAG, it print out "Thread running ", means thread is working.
However it can not print out this->tickQue.back().askPrice1; it shows queue error.
How does thread read this queue? Thanks for any help.
Related
response print 0 instead of 999. What the proper way to read the response of the signal in this example?
class Worker : public QObject {
Q_OBJECT
public:
Worker()
{
connect(this, &Worker::signalTest, this, [this] (int x)
{
this->Test(x);
});
};
int Test(int x)
{
qDebug() << "x: " << x;
return 999;
}
public slots:
signals:
int signalTest(int x);
};
QThread* thread = new QThread();
Worker* worker = new Worker();
worker->moveToThread(thread);
thread->start();
int response = emit worker->signalTest(10);
qDebug() << "response: " << response;
You need to read how to use signals slots correctly in Qt. You need to write a slot that accepts int response as input. And connect the signal to this slot with the QueuedConnection flag
Documentation: https://doc.qt.io/qt-6/signalsandslots.html
class Worker : public QObject {
Q_OBJECT
public:
Worker()
{
connect(this, &Worker::signalTest, this, [this] (int x)
{
this->Test(x);
});
};
int Test(int x)
{
qDebug() << "x: " << x;
emit signalResp(999);
}
public slots:
void slotResp(int x)
{
qDebug() << "responce" << x;
}
signals:
int signalTest(int x);
void signalResp(int x);
};
QThread* thread = new QThread();
Worker* worker = new Worker();
worker->moveToThread(thread);
connect(worker, SIGNAL(signalResp(int), worker, SLOT(slotResp(int)), Qt::QueuedConnection);
thread->start();
emit worker->signalTest(10);
I want to make the MainWindow receive the signals emitted from QToolButtons, and then do something in the slot function according to the index sent from QToolButtons. When I compiled the project, no error occurred. But when I clicked these toolbuttons, nothing happened and the log didn't get printed. I think there's something wrong with the signal or slot, but the program runs with no errors, so I don't know how to find the solution.
MainWindow.cpp:
MainWindow::MainWindow(QWidget* parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
this->setWindowTitle(MainWindowTitle);
setWindowIcon(QIcon(":/res/icons/logo.ico"));
signalMapper = new QSignalMapper(this);
initLayout();
}
void MainWindow::initLayout()
{
// initialize sidebar buttons
initSideBar();
// initialize QStackedWidget
/* initialize CodePage */
codePage = new CodePage(this);
ui->stackedWidget->addWidget(codePage);
ui->stackedWidget->setCurrentWidget(codePage);
/* initialize Charts */
qCharts = new ThemeWidget();
ui->stackedWidget->addWidget(qCharts);
// ui->stackedWidget->setCurrentWidget(qCharts);
}
void MainWindow::initSideBar()
{
QStringList btn_bgImages;
QStringList btn_names;
btn_bgImages << ":res/sidebar/code.png" << ":res/sidebar/pencil.png" << ":res/sidebar/visualize.png" << ":res/sidebar/graph.png";
btn_names << "Editor" << "Designer" << "Visualize" << "Charts";
for(int i = 0; i < btn_bgImages.size(); i++)
{
cTabButton* ctBtn = new cTabButton(btn_bgImages.at(i));
ctBtn->setText(btn_names.at(i));
connect(ctBtn, SIGNAL(&QAbstractButton::clicked), signalMapper, SLOT(&QSignalMapper::map));
signalMapper->setMapping(ctBtn, i);
ui->sidebar->addWidget(ctBtn, 0, Qt::AlignTop);
}
QObject::connect(signalMapper, SIGNAL(map), this, SLOT(MainWindow::switchPage));
}
void MainWindow::switchPage(int index)
{
qDebug() << "switchPage() triggered";
switch(index)
{
case 0:
qStackedWidget->setCurrentWidget(codePage);
break;
case 1:
break;
case 2:
break;
case 3:
qStackedWidget->setCurrentWidget(qCharts);
break;
default:
break;
}
}
MainWindow.h:
QT_BEGIN_NAMESPACE
namespace Ui
{
class MainWindow;
}
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget* parent = nullptr);
~MainWindow();
private slots:
void switchPage(int);
private:
Ui::MainWindow* ui;
CodeEditor* configEditor;
QListView* sidebar;
QStackedWidget* qStackedWidget;
CodePage* codePage;
ThemeWidget* qCharts;
QSignalMapper* signalMapper;
void initSideBar();
void initLayout();
};
cTabButton.h
class cTabButton : public QToolButton{
Q_OBJECT
public:
cTabButton(const QString& path, QWidget *parent=0);
~cTabButton();
protected:
QString path;
bool m_mousePressed;
bool m_mouseHover;
void doPaintStuff(int topColor, int centerColor, int bottomColor);
void setButtonPressed(bool isPressed);
void enterEvent(QEnterEvent *);
void leaveEvent(QEvent *);
void paintEvent(QPaintEvent *event);
void mousePressEvent(QMouseEvent *event);
};
It looks like you are connecting to the wrong signal of QSignalMapper. Since you map to an integer, you want to connect to QSignalMapper::mappedInt:
QObject::connect(signalMapper, &QSignalMapper::mappedInt, this, &MainWindow::switchPage);
I have a question how to override the signal in Qt?
I have redefined QCheckBox() and changed stateChanged signal.
The project is bilding and working. It does not output in the "application output" errors or messages of the " signal with the slot is not connected"
BUT it doesn't link to the slot. I can't figure out what's wrong.
This code works :
connect(test_checkbox[i], SIGNAL(stateChanged(int)), two_cl , SLOT(run_NEW()));
I need to emit string in addition to the number :
connect(test_checkbox[i], SIGNAL(stateChanged(int, QString)), two_cl , SLOT(run_NEW(int, QString)));
override QCheckBox
.h
#ifndef MYDIMASCHECKBOX_H
#define MYDIMASCHECKBOX_H
#include <QCheckBox>
class MyDimasCheckBox : public QCheckBox
{
Q_OBJECT
public:
MyDimasCheckBox(QWidget *parent =0);
~MyDimasCheckBox();
QString stroka;
signals:
void stateChanged(int, QString);
};
#endif // MYDIMASCHECKBOX_H
.cpp
#include "mydimascheckbox.h"
MyDimasCheckBox::MyDimasCheckBox(QWidget *parent)
{
stroka = "dimasik :3";
emit stateChanged(int(), stroka);
}
MyDimasCheckBox::~MyDimasCheckBox()
{
}
And here is where challenge
.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QCheckBox>
#include <QHBoxLayout>
#include <QDebug>
#include <QThread>
#include <QCoreApplication>
#include <iostream>
#include <vector>
#include "mydimascheckbox.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
int glob_i ;
int glob_flow;
int vector_schet;
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
void start_sending(bool);
private slots:
void on_pushButton_clicked();
private:
Ui::MainWindow *ui;
QThread *thread = new QThread();
QVector<QThread*> vector_thread;
QList<MyDimasCheckBox*> test_checkbox;
MyDimasCheckBox *checkBox = new MyDimasCheckBox();
QWidget *checkBoxWidget = new QWidget();
QHBoxLayout *layoutCheckBox = new QHBoxLayout(checkBoxWidget);
};
class NewsThread: public QThread
{
Q_OBJECT
public slots:
void run_NEW();
void run_NEW(int, QString);
signals:
void otprawka (int);
};
#endif // MAINWINDOW_H
.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
glob_i=0;
glob_flow =0;
vector_schet =0;
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
test_checkbox.clear();
}
void MainWindow::on_pushButton_clicked()
{
glob_i++;
checkBoxWidget = new QWidget();
checkBox = new MyDimasCheckBox();
layoutCheckBox = new QHBoxLayout(checkBoxWidget);
test_checkbox.append(checkBox);
connect(checkBox, SIGNAL(toggled(bool)),this, SLOT(start_sending(bool)));
checkBox->setText(QString::number(glob_i));
layoutCheckBox->addWidget(checkBox);
layoutCheckBox->setAlignment(Qt::AlignCenter);
layoutCheckBox->setContentsMargins(0,0,0,0);
ui->tW_test->insertRow(ui->tW_test->rowCount());
ui->tW_test->setCellWidget(ui->tW_test->rowCount()-1, 1, checkBoxWidget);
qDebug() << "glob_i: " << glob_i;
}
void MainWindow::start_sending(bool Value)
{
qDebug() << "start_sending " ;
// когда нажата отрабатывает, отжата то не отрабатывает
if (Value == true)
{
NewsThread *two_cl = new NewsThread();
qDebug() << "chekbocks: "<< " TRUE" ;
for (int i =0;i < test_checkbox.length();i++ )
{
if(test_checkbox[i]->isChecked() ==Value)
{
glob_flow++;
// connect(test_checkbox[i], SIGNAL(stateChanged(int)), two_cl , SLOT(run_NEW()));
connect(test_checkbox[i], SIGNAL(stateChanged(int, QString)), two_cl , SLOT(run_NEW(int, QString)));
thread = new QThread();
vector_thread.append(thread);
vector_schet++;
qDebug() << "vector_schet : " << vector_schet ;
two_cl->moveToThread(vector_thread[vector_schet-1]);
vector_thread[vector_schet-1]->start();
}
}
}
else {
qDebug() << "chekbocks:" << " False";
glob_flow--;
qDebug() << "vector_schet : " << vector_schet ;
vector_thread[vector_schet-1]->exit();
}
}
void NewsThread::run_NEW()
{
qDebug() << "run_NEW()";
for(;;){
for (int i=0; i<500; i++){
qDebug()<< "Число :" << i <<"number \"flow\" :" ;
usleep(100000);
}
}
}
void NewsThread::run_NEW(int i, QString str){
qDebug() << "run_NEW(int i, QString str) ";
for(;;){
for (int i=0; i<500; i++){
qDebug() << " i : " << i;
qDebug() << " str : " << str;
qDebug()<< "Число :" << i <<"number \"flow\" :" ;
usleep(100000);
}
}
}
You cannot replace a signal with another signal in a subclass. You can, however, emit an additional signal with the original signal in a self-connected slot:
class MyDimasCheckBox : public QCheckBox
{
Q_OBJECT
public:
MyDimasCheckBox(QWidget *parent =0);
~MyDimasCheckBox();
QString stroka;
private slots:
// Emits the new signal
void doEmitStateChanged(int i);
signals:
void stateChanged(int, QString);
};
MyDimasCheckBox::MyDimasCheckBox(QWidget *parent) : QCheckBox(parent) {
// Connect original signal to slot
connect(this, SIGNAL(stateChanged(int)), this, SLOT(doEmitStateChanged(int)));
}
void MyDimasCheckBox::doEmitStateChanged(int i) {
emit stateChanged(i, stroka);
}
With the new connection syntax, you can omit the slot and use a lambda:
connect(this, qOverload<int>(&QCheckBox::stateChanged),
// "this" context-object for QThread-Affinity
this, [=](int i) { emit this->stateChanged(i, this->stroka); });
Overriding signal is a bad practice [1]:
"APIs with overridden signals are hard to use, unexpected and bug-prone. To make it worse, Qt even allows you to override a signal with a non-signal, and vice-versa."
https://www.kdab.com/nailing-13-signal-slot-mistakes-clazy-1-3/
I have been trying to get this simple example using threads activated by pushbuttons to work. It is based off of the solution in the question below:
How to implement frequent start/stop of a thread (QThread)
The main differences between the example solution above and my code below are:
I used a QWidget instead of MainWindow
I changed the name of signals for clarity
My code contains debugging information
I experimented with eliminating the signals created by worker as the didn't appear to do anything
It appears that the start/stop signals are not triggering their corresponding slots, but I am not experienced enough to troubleshoot why.
Additionally, I am unsure of the purpose of the signal:
SignalToObj_mainThreadGUI()
Is that just something that could be used and is not?
I have been trying to get this code to work for some time, so any help would be greatly appreciated.
main.cpp
#include "threadtest.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
ThreadTest w;
w.show();
return a.exec();
}
threadtest.h
#include <QWidget>
#include <QThread>
#include "worker.h"
namespace Ui
{
class ThreadTest;
}
class ThreadTest : public QWidget
{
Q_OBJECT
public:
explicit ThreadTest(QWidget *parent = 0);
~ThreadTest();
signals:
void startWorkSignal();
void stopWorkSignal();
private slots:
void on_startButton_clicked();
void on_stopButton_clicked();
private:
Ui::ThreadTest *ui;
worker *myWorker;
QThread *WorkerThread;
};
threadtest.cpp
#include "threadtest.h"
#include "ui_threadtest.h"
ThreadTest::ThreadTest(QWidget *parent) :
QWidget(parent),
ui(new Ui::ThreadTest)
{
ui->setupUi(this);
myWorker = new worker;
WorkerThread = new QThread;
myWorker->moveToThread(WorkerThread);
connect(this,
SIGNAL(startWorkSignal()),
myWorker,
SLOT(StartWork())
);
connect(this,
SIGNAL(stopWorkSignal()),
myWorker,
SLOT(StopWork())
);
//Debug
this->dumpObjectInfo();
myWorker->dumpObjectInfo();
}
ThreadTest::~ThreadTest()
{
delete ui;
}
void ThreadTest::on_startButton_clicked()
{
qDebug() << "startwork signal emmitted";
emit startWorkSignal();
}
void ThreadTest::on_stopButton_clicked()
{
qDebug() << "stopwork signal emmitted";
emit stopWorkSignal();
}
worker.h
#include <QObject>
#include <QDebug>
class worker : public QObject {
Q_OBJECT
public:
explicit worker(QObject *parent = 0);
~worker();
signals:
void SignalToObj_mainThreadGUI();
//void running();
//void stopped();
public slots:
void StopWork();
void StartWork();
private slots:
void do_Work();
private:
volatile bool running, stopped;
};
worker.cpp
#include "worker.h"
worker::worker(QObject *parent) : QObject(parent), stopped(false),
running(false)
{
qDebug() << "running: " << running;
qDebug() << "stopped: " << stopped;
}
worker::~worker() {}
void worker::do_Work()
{
qDebug() << "inside do Work";
emit SignalToObj_mainThreadGUI();
if (!running || stopped) return;
// actual work here
/*
for (int i = 0; i < 100; i++)
{
qDebug() << "count: " + i;
}
*/
QMetaObject::invokeMethod(this, "do_Work", Qt::QueuedConnection);
}
void worker::StopWork()
{
qDebug() << "inside StopWork";
stopped = true;
running = false;
//emit stopped();
}
void worker::StartWork()
{
qDebug() << "inside StartWork";
stopped = false;
running = true;
//emit running();
do_Work();
}
You should write
WorkerThread->start();
Or you can use the thread of the ThreadTest object instead the WorkerThread (in this case the WorkerThread is needless):
myWorker->moveToThread(thread()); // this->thread
The slots are not triggered, because you have moved myWork to the thread WorkerThread, but didnot run an event loop in that thread. In threadtest.cpp, add
WorkerThread .start();
after
myWorker = new worker;
WorkerThread = new QThread;
myWorker->moveToThread(WorkerThread);
I want to modify a Qlist by reference in a thread because the sorting could take a few seconds.
But it seems like that I can't modify the List. Outside of the thread the List has not beend changed.
In QMainwindow:
QThread *thread = new QThread();
FarmSortWorker *farmsort_worker = new FarmSortWorker();
farmsort_worker->setFarmData(farm_list);
farmsort_worker->moveToThread(thread);
connect(farmsort_worker, &FarmSortWorker::error, [=](QString error_msg){
qDebug() << error_msg;
logger->logEvent(error_msg, Logger::ERROR);
});
connect(thread, &QThread::started, farmsort_worker, &FarmSortWorker::processSort);
connect(farmsort_worker, &FarmSortWorker::finished, thread, &QThread::quit);
connect(farmsort_worker, &FarmSortWorker::finished, farmsort_worker, &QThread::deleteLater);
connect(thread, &QThread::finished, thread, &QThread::deleteLater);
thread->start();
My Thread (.h)
#ifndef FARMSORTWORKER_H
#define FARMSORTWORKER_H
#include <QObject>
#include "../framcontainer.h"
#include <QList>
#include <qDebug>
#include <QString>
class FarmSortWorker : public QObject
{
Q_OBJECT
public:
explicit FarmSortWorker(QObject *parent = 0);
~FarmSortWorker();
void setFarmData(QList<FramContainer> &farm_container);
private:
QList<FramContainer> farm_container;
signals:
void error(QString error);
void finished();
public slots:
void processSort();
};
#endif // FARMSORTWORKER_H
My Thread (.cpp)
#include "farmsortworker.h"
FarmSortWorker::FarmSortWorker(QObject *parent) :
QObject(parent)
{
}
FarmSortWorker::~FarmSortWorker()
{
}
void FarmSortWorker::setFarmData(QList<FramContainer> &farm_container)
{
this->farm_container = farm_container;
}
void FarmSortWorker::processSort()
{
qDebug() << "count:" << farm_container.size();
for(int i = 0; i < farm_container.size(); i++)
{
FramContainer park = farm_container.at(i);
qDebug() << "original:" << park.getFarmName();
}
for(int i = 0; i < farm_container.size(); i++)
{
FramContainer *park =& farm_container[i];
park->setFarmName("test");
}
for(int i = 0; i < farm_container.size(); i++)
{
FramContainer park = farm_container.at(i);
qDebug() << "neu:" << park.getFarmName();
}
emit finished();
}
Thank you all in advance.
It's because you save a copy of the list in your thread class, not a reference.
Instead of having a separate function to set the list, pass it (by reference) to the constructor, and have it set the reference variable:
class FarmSortWorker : public QObject
{
Q_OBJECT
public:
explicit FarmSortWorker(QList<FramContainer>& list, QObject *parent = 0);
...
private:
QList<FramContainer>& farm_container; // Store as a reference
...
};
...
FarmSortWorker::FarmSortWorker(QList<FramContainer>& list, QObject *parent) :
QObject(parent), farm_container(list)
{
}
...
QThread *thread = new QThread();
FarmSortWorker *farmsort_worker = new FarmSortWorker(farm_list);
...