How to override a signal in qt? - c++

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/

Related

how can QThread read queue?

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.

Send parameters with dynamically generated QComboBox

I want to insert a QComboBox inside a QTableWidget. When I change the Index of the CB I'll call a methode to change the status in the sqlite table. But for this, I need do pass two parameters to the methode. The ID(First element of the row), and the current index of the CB.
I generate the QTableWidget like that:
...
for(int i = 0; i < dbModel->rowCount();i++){
row = dbModel->record(i);
ui->tW_Services->setItem(i,0,new QTableWidgetItem(row.field(0).value().toString()));
ui->tW_Services->setItem(i,1,new QTableWidgetItem(row.field(1).value().toString()));
ui->tW_Services->setItem(i,2,new QTableWidgetItem(row.field(2).value().toString()));
ui->tW_Services->setItem(i,3,new QTableWidgetItem(row.field(3).value().toString()));
ui->tW_Services->setItem(i,4,new QTableWidgetItem(row.field(4).value().toString() + "€"));
ui->tW_Services->setItem(i,5,new QTableWidgetItem(row.field(5).value().toString() + "€"));
//ui->tW_Services->setItem(i,6,new QTableWidgetItem(row.field(6).value().toString()));
QComboBox* combo = new QComboBox();
combo->addItem("open");
combo->addItem("paid");
if(row.field(6).value().toString() != "paid") combo->setCurrentIndex(0);
else combo->setCurrentIndex(1);
connect(combo, SIGNAL(currentIndexChanged(int)), this, SLOT(onComboChanged(int)));
ui->tW_Services->setCellWidget(i,6,combo);
}
...
and the slot looks like that:
void MainWindow::onComboChanged(int ID)
{
qDebug() << "ID:" << QString::number(ID);
}
But when I try to create the method with 2 args:
void MainWindow::onComboChanged(int ID,int index)
{
qDebug() << "ID:" << QString::number(ID);
}
and attach a second parameter and calling the slot like:
connect(combo, SIGNAL(currentIndexChanged(int)), this, SLOT(onComboChanged(row.field(0).value().toInt(),int)));
I get:
qt.core.qobject.connect: QObject::connect: No such slot MainWindow::onComboChanged(row.field(0).value().toInt(),int)
A minimal reproducible example:
There's just a single pushbutton and a qtablewidget
mainwindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
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 on_pushButton_clicked();
void onComboChanged(int ID, int index);
void onComboChanged2(int index);
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
mainwindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QComboBox>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
ui->tableWidget->setColumnCount(4);
ui->tableWidget->setRowCount(3);
for(int i = 0; i < 3;i++){
ui->tableWidget->setItem(i,0,new QTableWidgetItem(QString::number(i)));
ui->tableWidget->setItem(i,1,new QTableWidgetItem("Test"));
ui->tableWidget->setItem(i,2,new QTableWidgetItem("Test 2"));
QComboBox* combo = new QComboBox();
combo->addItem("open");
combo->addItem("paid");
combo->setCurrentIndex(0);
int j = i+1;
//NOT WORKING
//connect(combo, SIGNAL(currentIndexChanged(int)),this,
// [=](int index) {this->onComboChanged(j, index);});
//WORKING
//connect(combo, SIGNAL(currentIndexChanged(int)),SLOT(onComboChanged2(int)));
ui->tableWidget->setCellWidget(i,3,combo);
}
}
void MainWindow::onComboChanged(int ID, int index)
{
qDebug() << "ID: " << ID << "index: "<< index;
}
void MainWindow::onComboChanged2(int index)
{
qDebug() << "ID: " << index;
}
Since currentIndexChanged only has one parameter, your slot cannot capture more than that. But, since the row ID does not change on emission, you can wrap onComboChanged into a lambda as shown here, which captures the row by copy:
connect(combo, &QComboBox::currentIndexChanged,
this, [=](int index) {this->onComboChanged(i, index);});
Since your code is not a minimal reproducible example, I could not test this. Let me know, if it doesn't work.

How to get a variable from a thread?

I have a class that creates a server with multithreading. With the help of multithreading, I can connect several users at the same time. In one stream, the QByteArray Data is written, but I need this variable in the lane or in the lane heder, so that I can output this line (i.e., QByteArray Data). How I can tranfer var Data in my main function or header main?
I want write Data in QLable or somthing...
main.c
#include "groundstation.h"
#include <QApplication>
#include "server.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
GroundStation w;
Server wServer;
wServer.StartServer();
//qDebug() << ServerThread::getString();
// QLabel *label = new QLabel();
//label->setText((QString));
w.show();
return a.exec();
}
server.cpp
#include "server.h"
Server::Server(QObject *parent) :
QTcpServer (parent)
{
}
void Server::StartServer(){
if(!this->listen(QHostAddress::Any, 1234)){
qDebug() << "Could not start server";
}
else {
qDebug() << "Listening...";
}
}
void Server::incomingConnection(int socketDescriptor){
qDebug() << socketDescriptor << "Connecting...";
ServerThread *thread = new ServerThread(socketDescriptor, this);
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
}
sever.h
#ifndef SERVER_H
#define SERVER_H
#include <QTcpServer>
#include <QDebug>
#include "serverthread.h"
class Server : public QTcpServer
{
Q_OBJECT
public:
explicit Server(QObject *parent = 0);
void StartServer();
signals:
public slots:
protected:
void incomingConnection(int socketDescriptor);
};
#endif // SERVER_H
serverthread.cpp
#include "serverthread.h"
ServerThread::ServerThread(int id, QObject *parent) :
QThread (parent)
{
this->socketDescriptor = id;
}
void ServerThread::run(){
//thread starts here
qDebug() << socketDescriptor << " Starting thread";
socket = new QTcpSocket();
if(!socket->setSocketDescriptor(this->socketDescriptor)){
emit error(socket->error());
return;
}
connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()), Qt::DirectConnection);
connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected()), Qt::DirectConnection);
qDebug() << socketDescriptor << " Client connected";
//make this thread a loop
exec();
}
void ServerThread::readyRead(){
Data = socket->readAll();
qDebug() << socketDescriptor << " Data in: " << Data;
socket->write(Data);
}
void ServerThread::disconnected(){
qDebug() << socketDescriptor << " Disconnected";
socket->deleteLater();
exit(0);
}
serverthread.h
#ifndef SERVERTHREAD_H
#define SERVERTHREAD_H
#include <QThread>
#include <QTcpSocket>
#include <QDebug>
class ServerThread : public QThread
{
Q_OBJECT
public:
QByteArray Data;
explicit ServerThread(int id, QObject *parent = 0);
void run();
signals:
void error(QTcpSocket::SocketError socketerror);
public slots:
void readyRead();
void disconnected();
public slots:
private:
QTcpSocket *socket;
int socketDescriptor;
};
#endif // SERVERTHREAD_H

Redirect qDebug to an emitted signal

I've successfully redirected qDebug() output to a QTextEdit widget. For several reasons, I'd like every qDebug() message to be included in an emitted signal. One reason is that the object which shall receive the output isn't available. Another reason is that I want to redirect the output to different objects depending on which activity is active at the moment (using connect/disconnect of the signal to different slots).
I've made a working example code that redirects qDebug to a QTextEdit widget. Can someone please help me to get this code to emit a signal which includes the qDebug message?
I'm not sure if its possible to have Q_DebugStream emit a signal (I've tried and failed to make a Qt Class out of it).
It must be possible to pass a pointer to a function/slot instead of a pointer to a QTextEdit when calling Q_DebugStream, but I'm not sure how this is done.
mainwindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QTextEdit>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
signals:
void logSignal(QString);
public slots:
void logSlot(QString);
private:
QTextEdit *logView;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "q_debugstream.h"
#include <QGridLayout>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
QWidget *mainWidget = new QWidget(this);
setCentralWidget(mainWidget);
logView = new QTextEdit;
QGridLayout *mainLayout = new QGridLayout;
mainLayout->addWidget(logView,0,0,1,1);
mainWidget->setLayout(mainLayout);
connect(this, SIGNAL(logSignal(QString)),
this, SLOT(logSlot(QString)));
emit logSignal("Message from a signal\n");
new Q_DebugStream(std::cout, logView); //Redirect Console output to QTextEdit
Q_DebugStream::registerQDebugMessageHandler(); //Redirect qDebug() output to QTextEdit
qDebug() << "DEBUG MODE ACTIVE";
}
MainWindow::~MainWindow(){}
void MainWindow::logSlot(QString log) {
logView->append(log);
}
q_debugstream.h
//As per forum:
//http://www.qtforum.org/article/39768/redirecting-std-cout-std-cerf-qdebug-to-qtextedit.html
//A couple of lines added to ensure newlines go between each call.
//Thanks, James!
#ifndef Q_DEBUGSTREAM_H
#define Q_DEBUGSTREAM_H
#include <iostream>
#include <streambuf>
#include <string>
#include <QTextEdit>
class Q_DebugStream : public std::basic_streambuf<char>
{
public:
Q_DebugStream(std::ostream &stream, QTextEdit* text_edit) : m_stream(stream)
{
log_window = text_edit;
m_old_buf = stream.rdbuf();
stream.rdbuf(this);
}
~Q_DebugStream()
{
m_stream.rdbuf(m_old_buf);
}
static void registerQDebugMessageHandler(){
qInstallMessageHandler(myQDebugMessageHandler);
}
private:
static void myQDebugMessageHandler(QtMsgType, const QMessageLogContext &, const QString &msg)
{
std::cout << msg.toStdString().c_str();
}
protected:
//This is called when a std::endl has been inserted into the stream
virtual int_type overflow(int_type v)
{
if (v == '\n')
{
log_window->append("");
}
return v;
}
virtual std::streamsize xsputn(const char *p, std::streamsize n)
{
QString str(p);
if(str.contains("\n")){
QStringList strSplitted = str.split("\n");
log_window->moveCursor (QTextCursor::End);
log_window->insertPlainText (strSplitted.at(0)); //Index 0 is still on the same old line
for(int i = 1; i < strSplitted.size(); i++){
log_window->append(strSplitted.at(i));
log_window->append("\n");
}
}else{
log_window->moveCursor (QTextCursor::End);
log_window->insertPlainText (str);
log_window->insertPlainText ("\n");
}
return n;
}
private:
std::ostream &m_stream;
std::streambuf *m_old_buf;
QTextEdit* log_window;
};
#endif // Q_DEBUGSTREAM_H
When application is started, I get both messages in my QTextEdit:
"Message from a signal"
"DEBUG MODE ACTIVE"
(This answer extracted from an edit to the question - now rolled back).
Here's how I solved this:
mainwindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QTextEdit>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
signals:
void logSignal(QString);
public slots:
void logSlot(QString);
private:
void dbgMsg(QString);
QTextEdit *logView;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "q_debugstream.h"
#include <QGridLayout>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
QWidget *mainWidget = new QWidget(this);
setCentralWidget(mainWidget);
logView = new QTextEdit;
QGridLayout *mainLayout = new QGridLayout;
mainLayout->addWidget(logView,0,0,1,1);
mainWidget->setLayout(mainLayout);
connect(this, SIGNAL(logSignal(QString)),
this, SLOT(logSlot(QString)));
emit logSignal("Now call Q_DebugStream");
//Redirect qDebug() output to dbgMsg(QString)
new Q_DebugStream(std::cout, this, &MainWindow::dbgMsg);
Q_DebugStream::registerQDebugMessageHandler();
qDebug() << "Debug message";
qWarning() << "Warning!";
qCritical() << "Critical issue!";
qInfo() << "Information";
qDebug() << "This\nis\na\nlong\none.";
}
MainWindow::~MainWindow(){}
void MainWindow::logSlot(QString log) {
logView->append(log);
}
void MainWindow::dbgMsg(QString log) {
emit logSignal(log);
}
q_debugstream.h
#ifndef Q_DEBUGSTREAM_H
#define Q_DEBUGSTREAM_H
#include <iostream>
#include <streambuf>
#include <string>
#include <QString>
#include "mainwindow.h"
class Q_DebugStream : public std::basic_streambuf<char> {
public:
Q_DebugStream(std::ostream &stream, MainWindow* obj, void (MainWindow::*dbgMsgPtr)(QString log)): m_stream(stream) {
m_old_buf = stream.rdbuf();
stream.rdbuf(this);
msgObj = obj;
msgHandler = dbgMsgPtr;
}
~Q_DebugStream() {
m_stream.rdbuf(m_old_buf);
}
static void registerQDebugMessageHandler() {
qInstallMessageHandler(myQDebugMessageHandler);
}
private:
static void myQDebugMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg) {
QString message = msg;
switch (type) {
case QtDebugMsg:
message.prepend("qDbg(): ");
break;
case QtWarningMsg:
message.prepend("qWarn(): ");
break;
case QtCriticalMsg:
message.prepend("qCrit(): ");
break;
case QtInfoMsg:
message.prepend("qInfo(): ");
break;
case QtFatalMsg:
message.prepend("qFatal(): ");
abort();
break;
}
message.append(" (" + QString::fromUtf8(context.file) + ")");
message.append(" line: " + QString::number(context.line));
std::cout << message.toStdString().c_str();
}
protected:
//This is called when a std::endl has been inserted into the stream
virtual int_type overflow(int_type v) {
if (v == '\n') {
(msgObj->*msgHandler)("\n");
}
return v;
}
virtual std::streamsize xsputn(const char *p, std::streamsize n) {
QString str(p);
if(str.contains("\n")) {
QStringList strSplitted = str.split("\n");
(msgObj->*msgHandler)(strSplitted.at(0)); //Index 0 is still on the same old line
for(int i = 1; i < strSplitted.size(); i++) {
(msgObj->*msgHandler)("\\ " + strSplitted.at(i));
}
} else {
(msgObj->*msgHandler)(str);
}
return n;
}
private:
std::ostream &m_stream;
std::streambuf *m_old_buf;
MainWindow* msgObj;
void (MainWindow::*msgHandler)(QString);
};
#endif // Q_DEBUGSTREAM_H
When application is started, I get these messages in my QTextEdit:
Now call Q_DebugStream
qDbg(): Debug message (..\qDebugFetch\mainwindow.cpp) line: 25
qWarn(): Warning! (..\qDebugFetch\mainwindow.cpp) line: 26
qCrit(): Critical issue! (..\qDebugFetch\mainwindow.cpp) line: 27
qInfo(): Information (..\qDebugFetch\mainwindow.cpp) line: 28
qDbg(): This
\ is
\ a
\ long
\ one. (..\qDebugFetch\mainwindow.cpp) line: 29

Qt - Simple example using threads controlled by push buttons

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);