'QMessageBox::critical' : none of the 4 overloads could convert all the argument types - qt

I want to display an error message whenever my independent thread encounters the word "alert1" in a specific .txt file. But I get the above error inside the monitorForAlerts() inside mythread.cpp file. The line expectedly executes if I were to place it inside dialog.cpp. So I guess this is due to non-inheritance of this object. Can you please advise me how to solve this error for the given code?
Here is the code:
dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include <QtCore>
#include "mythread.h"
namespace Ui {
class Dialog;
}
class Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
public slots:
private:
Ui::Dialog *ui;
private slots:
void on_pushButton_clicked();
void on_pushButton_2_clicked();
};
#endif // DIALOG_H
mythread.h
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
#include <QtCore>
#include <QDebug>
#include <QFile>
#include <Windows.h>
#include <QMessageBox>
#include <QTimer>
#define ALERTS_MESSAGE_STORAGE_PATH "E:\\QT1\\simpleGUIThread2\\simpleGUIThread2\\usbAlert.txt"
#define TIMER_VALUE 500
class MyThread : public QThread
{
Q_OBJECT
public:
explicit MyThread(QObject *parent = 0);
void run();
QString name;
void monitorForAlerts();
int exec();
public slots:
signals:
void testSignal(QString message);
public slots:
};
#endif // MYTHREAD_H
dialog.cpp
#include "dialog.h"
#include "ui_dialog.h"
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
}
Dialog::~Dialog()
{
delete ui;
}
void Dialog::on_pushButton_clicked()
{
ui->label->show();
}
void Dialog::on_pushButton_2_clicked()
{
ui->label->hide();
}
mythread.cpp
#include "mythread.h"
#include "dialog.h"
MyThread::MyThread(QObject *parent) :
QThread(parent)
{
}
void MyThread::run()
{
exec();
}
int MyThread::exec()
{
while(1)
{
monitorForAlerts();
emit(testSignal("hello world!!"));
sleep(1);
}
}
void MyThread::monitorForAlerts()
{
QString response = ALERTS_MESSAGE_STORAGE_PATH;
QFile resp(response);
resp.open(QIODevice::WriteOnly);
resp.close();
QFile resp1(response);
char buf[121];
char buf1[] = "alert1";
char buf2[] = "alert2";
resp1.open(QIODevice::ReadOnly);
while(resp1.size() == 0)
{
Sleep(3000);
}
qint64 lineLength = resp1.readLine(buf, sizeof(buf));
resp1.close();
if(strcmp(buf,buf1) == 0)
{
QFile::remove(ALERTS_MESSAGE_STORAGE_PATH);
qDebug()<<"warning 1!!";
QMessageBox::critical(this,tr("ERROR"),tr("Large change in illumination.\nPlease re-capture reference image.\n"));
}
if(strcmp(buf,buf2) == 0)
{
QFile::remove(ALERTS_MESSAGE_STORAGE_PATH);
qDebug()<<"warning 2!!";
QMessageBox::critical(this,tr("ERROR"),tr("The camera position has been moved or an object is obscuring its view.\nPlease check the device.\n"));
}
}
main.cpp
#include "dialog.h"
#include <QApplication>
#include "mythread.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MyThread mThread1;
mThread1.name = "mThread1";
mThread1.start();
Dialog w;
w.show();
return a.exec();
}
LATEST UPDATE*********************************************************************
Hi Zlatomir,
I choose to take your 1st advice. I have created a signal that the thread will emit and connect it to a slot for QDialog. Please let me know if my understanding is correct, because I do not know where to implement the connect(), since the signal is declared in mythread.h and the slot in dialog.h. The connection type argument for connect is Qt::QueuedConnection, so that gui elements from another thread different than main-thread.
are NOT created. Is this statement correct? and where do I place this?
connect( mThread, SIGNAL(alertSignal(QString)), this, SLOT(alertSlot(QString)), Qt::QueuedConnection);
mythread.h
//....
signals:
void alertSignal(QString message);
//....
dialog.h
//....
public slots:
void alertSlot(QString message);
//....
mythread.cpp
//....
if(strcmp(buf,buf1) == 0)
{
QFile::remove(ALERTS_MESSAGE_STORAGE_PATH);
qDebug()<<"warning 1!!";
emit(alertSignal("alert1"));
}
else if(strcmp(buf,buf2) == 0)
{
QFile::remove(ALERTS_MESSAGE_STORAGE_PATH);
qDebug()<<"warning 2!!";
emit(alertSignal("alert2"));
}
dialog.cpp
void Dialog::alertSlot(QString message)
{
if(strcmp(message, "alert1"))
QMessageBox::critical(this,tr("ERROR"),tr("Large change in illumination.\nPlease re-capture reference image.\n"));
else if(strcmp(message, "alert2"))
QMessageBox::critical(this,tr("ERROR"),tr("The camera position has been moved or an object is obscuring its view.\nPlease check the device.\n"));
}
Now if this were correct, how do i implement the connect() and in which file?

The first argument is the problem, in your case this is not a good argument, because there this is a pointer to a MyThread instance, and MyThread is not a QWidget (is not derived from QWidget).
To solve this you can show the QMessageBox::critical from a slot in mainwindow (the Dialog class in your code, there you pass the instance of main-window that is a QWidget) and connect that slot with a signal that you emit from your thread, make sure that the connection type argument for connect is Qt::QueuedConnection, so that you don't try to create gui elements from another thread different than main-thread.
Another option would be to validate the data before you start the second thread and to tell
the user that he needs to provide the right files.
LE: Also check the QThread's documentation for the recommended way to use the class, now it's recommended not to derive from QThread.
LE2 - answer to the update
That connect can be made where ever you can have the two instances that you want to connect, in your case main.cpp is a good place to connect those (don't forget to fully qualify the name for connect: QObject::connect):
//...
MyThread mThread1;
mThread1.name = "mThread1";
mThread1.start();
Dialog w;
QObject::connect( &mThread1, SIGNAL(alertSignal(QString)), &w, SLOT(alertSlot(QString)), Qt::QueuedConnection);
w.show();
//...

Related

Qt : How to start , stop and delete thread?

=====================OUTDATE=======================
I have a vector which contains threads, each thread is doing a while loop, for some reason, i need to delete the thread in the vector, to do this, i referenced this blog and write a test demo online. But when i write pthread_cancel() in Qt, it reports error: use of undeclared identifier 'pthread_cancel'. I have added LIBS += -lpthread in my .pro file and added #include <thread> in my .cpp file, this error still exists.
=====================UPDATE=====================
Afterwards, i trid to use QThread to achieve my goal. In brief, to start a qthread, i create a Worker class, then instantiate it and move it to QThread, connect &QThread::started with &Worker::process, process is the time consuming method, finnaly call thread->start();; to stop a qthread, i use a bool flag, and i store it with thread id in QMap, if the bool flag is set to false, qthread will break while loop, and emit a finished() signal and this signal will trigger &QThread::quit; to delete the qthread, i connect finished() signal with &Worker::deleteLater and &QThread::deleteLater.
The code are:
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "worker.h"
#include <QThread>
#include <QMap>
#include <QDebug>
QMap<int, bool> stateController;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
ui->tableWidget->setSelectionMode(QAbstractItemView::SingleSelection);
qDebug()<<"Main UI thread id is"<<(int)QThread::currentThreadId();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_add_clicked()
{
int row = ui->tableWidget->rowCount();
ui->tableWidget->insertRow(row);
ui->tableWidget->setItem(row,0,new QTableWidgetItem());//hold a place for blank item, in order to uniformly determine whether its text is empty afterwards
QTableWidgetItem *ckx = new QTableWidgetItem;
ckx->setCheckState(Qt::Unchecked);
ui->tableWidget->setItem(row,1,ckx);
}
void MainWindow::on_tableWidget_cellClicked(int row, int column)
{
if(column == 1){
bool state = ui->tableWidget->item(row,1)->checkState();
if(state){
if(ui->tableWidget->item(row,0)->text().isEmpty()){//only if there is not thread id, then create the thread
QThread* thread = new QThread();
qDebug()<<"New created thread id is"<<(int)thread->currentThreadId(); //I found this thread id will equal to main ui thread id, so i use a sigal/slot to update thread id
Worker* worker = new Worker(row);
worker->moveToThread(thread);
connect( worker, &Worker::updateQThreadIDSignal, this, &MainWindow::updateQThreadID);
connect( thread, &QThread::started, worker, &Worker::process);
connect( worker, &Worker::finished, thread, &QThread::quit);
// automatically delete thread and worker object when work is done:
connect( worker, &Worker::finished, worker, &Worker::deleteLater);
connect( thread, &QThread::finished, thread, &QThread::deleteLater);
//start the thread
thread->start();
}
}else{
if(!ui->tableWidget->item(row,0)->text().isEmpty()){//only if there is already the thread, then stop it
int thread_id = ui->tableWidget->item(row,0)->text().toInt();
// qDebug()<<"get thread id is"<<thread_id;
QMutexLocker locker(&mx);
stateController[thread_id] = false;
ui->tableWidget->setItem(row,0,new QTableWidgetItem());//Because thread will be delete later, so clear its thread id
}
}
}
}
void MainWindow::on_pushButton_delete_clicked()
{
QItemSelectionModel* selectionModel = ui->tableWidget->selectionModel();
QModelIndex index = selectionModel->currentIndex();
if(index.isValid()){
int row = index.row();
if(!ui->tableWidget->item(row,0)->text().isEmpty()){//Before stop the thread, ensure it exist
int thread_id = ui->tableWidget->item(row,0)->text().toInt();
if(ui->tableWidget->item(row,1)->checkState() == Qt::Checked){
//If not stopped yet, firstly stop it
QMutexLocker locker(&mx);
stateController[thread_id] = false;
}
stateController.remove(thread_id);
}
ui->tableWidget->removeRow(row);
}
}
void MainWindow::updateQThreadID(int row, QString id)
{
ui->tableWidget->setItem(row,0,new QTableWidgetItem(QString::number(id.toInt())));
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QMutex>
#include <vector>
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_add_clicked();
void on_tableWidget_cellClicked(int row, int column);
void on_pushButton_delete_clicked();
public slots:
void updateQThreadID(int row, QString id);
private:
Ui::MainWindow *ui;
QMutex mx;
};
#endif // MAINWINDOW_H
worker.cpp
#include "worker.h"
#include <QThread>
#include <QDebug>
#include <QMutexLocker>
extern QMap<int, bool> stateController;
Worker::Worker(int row) : row_index(row) {
qDebug()<<"Create new worker at thread "<<(int)QThread::currentThreadId();
}
Worker::~Worker() {
qDebug()<<"Destroy the worker instance";
}
void Worker::process() {
thread_id = (int)QThread::currentThreadId();
stateController.insert(thread_id, true);
// qDebug()<<"set thread id is"<<thread_id;
emit updateQThreadIDSignal(row_index,QString("%1").arg(thread_id)); //execute once, because if delete row happen, the row index will change
while(true)
{
count++;
QThread::sleep(2);//simulate time consuming operations
qDebug()<<thread_id<<"processing"<<count;
{//life scope of locker
QMutexLocker locker(&mx);
if(!stateController[thread_id])//In every loop, determine whether it can run, if not, exit the loop
{
return;
}
}
}
emit finished();
}
worker.h
#ifndef WORKER_H
#define WORKER_H
#include <QObject>
#include <QMutex>
class Worker : public QObject {
Q_OBJECT
public:
Worker(int row);
~Worker();
public slots:
void process();
signals:
void finished();
void updateQThreadIDSignal(int, QString);
private:
int thread_id;
int row_index;
QMutex mx;
int count = 0;
};
#endif // WORKER_H
To watch the demo video, click here.
If you have any advice, please let me know, thanks !
Even though the codes seems to work fine, but i still have a question : Why i wrote &Worker::deleteLater, but I never see the destructor of Worker is called ?

How to properly stop QTimer from another thread

I see that such topic was discussed many times, but can't find clear answer to simple situation. I have Worker class running in the own thread where I create timer and want to stop it due to some condition.
But I am getting the error:
Timers cannot be stopped from another thread
I fill that am missing some core logic in thread working in Qt. Can someone please explain how to resolve that? Thank you.
Here is the main.cpp
#include <QCoreApplication>
#include <QObject>
#include <QtDebug>
#include "worker.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Worker w;
return a.exec();
}
Worker.h
#ifndef WORKER_H
#define WORKER_H
#include <QObject>
#include <QTimer>
#include <QThread>
#include <QtDebug>
class Worker : public QObject
{
Q_OBJECT
public:
explicit Worker(QObject *parent = nullptr);
private:
QThread t;
QTimer *timer;
int count = 1;
public slots:
void dataTimerFunction();
void onStopTimer(QTimer *t);
signals:
void stopTimer(QTimer *t);
};
#endif // WORKER_H
Worker.cpp
#include "worker.h"
Worker::Worker(QObject *parent) : QObject(parent)
{
this->moveToThread(&t);
QObject::connect(&t, &QThread::finished, this, &QObject::deleteLater);
t.start();
// are we in the new thread from this point, right?
timer = new QTimer();
QObject::connect(timer, &QTimer::timeout, this, &Worker::dataTimerFunction);
QObject::connect(this, &Worker::stopTimer, this, &Worker::onStopTimer);
// QObject::connect(this, &Worker::stopTimer, this, &Worker::onStopTimer, Qt::QueuedConnection); doesn't work as well
timer->start(200);
}
void Worker::dataTimerFunction()
{
qDebug()<<count;
count++;
if (count>5){
emit stopTimer(timer);
//timer->stop();
}
}
void Worker::onStopTimer(QTimer *t)
{
t->stop();
}
The problem is indeed that the timer is not moved to your thread.
Here is a modified worker class, that does what you might want to achieve. It moves the timer also to the thread and then starts and stops it by using signals / slots.
worker.h
#ifndef WORKER_H
#define WORKER_H
#include <QObject>
#include <QTimer>
#include <QThread>
#include <QtDebug>
class Worker : public QObject
{
Q_OBJECT
public:
explicit Worker(QObject *parent = nullptr);
private:
QThread t;
QTimer *timer;
int count = 1;
signals:
void stopTimer();
void startTimer(int msec);
public slots:
void dataTimerFunction();
};
#endif // WORKER_H
worker.cpp
#include "worker.h"
Worker::Worker(QObject *parent) : QObject(parent)
{
// are we in the new thread from this point, right?
timer = new QTimer(nullptr);
this->moveToThread(&t);
timer->moveToThread(&t);
QObject::connect(&t, &QThread::finished, this, &QObject::deleteLater);
t.start();
QObject::connect(timer, &QTimer::timeout, this, &Worker::dataTimerFunction);
QObject::connect(this, &Worker::stopTimer, timer, &QTimer::stop, Qt::QueuedConnection);
QObject::connect(this, &Worker::startTimer, timer, static_cast<void (QTimer::*)(int)>(&QTimer::start), Qt::QueuedConnection);
startTimer(200);
}
void Worker::dataTimerFunction()
{
qDebug()<<count;
count++;
if (count>5){
stopTimer();
}
}
You should new your timer in your task object slot, not in the task construtor. Stop the timer when your task object is deleted.
My task object header: Worker.h
#pragma once
#include <QObject>
class QTimer;
class Worker : public QObject
{
Q_OBJECT
public:
explicit Worker(QObject *parent = nullptr);
~Worker();
public slots:
void WorkerTaskStartSlot(void);
void TaskFinished(void);
private slots:
void TimerOutToDoSomethingSlot(void);
signals:
void WorkertResultSig(void);
private:
QTimer *m_pTimer = nullptr;
};
Worker.cpp:
#include "Worker.h"
#include <QDebug>
#include <QThread>
#include <QTimer>
Worker::Worker(QObject *parent) : QObject(parent)
{
qDebug()<<__FUNCTION__<<"threadid"<< QThread::currentThreadId();
}
Worker::~Worker()
{
TaskFinished();
qDebug()<<__FUNCTION__<<"threadid"<< QThread::currentThreadId();
}
void Worker::WorkerTaskStartSlot(void)
{
qDebug()<<__FUNCTION__<<"threadid"<< QThread::currentThreadId();
emit WorkertResultSig();
m_pTimer = new QTimer(this);
connect(m_pTimer,&QTimer::timeout,this,&Worker::TimerOutToDoSomethingSlot);
m_pTimer->start(1000);
}
void Worker::TaskFinished(void)
{
qDebug()<<__FUNCTION__<<"threadid"<< QThread::currentThreadId();
if(m_pTimer)
{
if(m_pTimer->isActive())
{
m_pTimer->stop();
qDebug()<<__FUNCTION__<<"stop timer"<< QThread::currentThreadId();
}
delete m_pTimer;
m_pTimer = nullptr;
}
}
void Worker::TimerOutToDoSomethingSlot(void)
{
qDebug()<<__FUNCTION__<<"threadid"<< QThread::currentThreadId();
}
The controller header: MainWindow.h
#pragma once
#include <QMainWindow>
class QPushButton;
class QWidget;
class Worker;
class QThread;
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
void InitCtrl(void);
private slots:
void StartTaskBtnSlot(const bool &checked);
void WorkertResultSlot(void);
private:
QPushButton *m_pStartTaskBtn = nullptr;
QWidget *m_pCenterWidget = nullptr;
Worker *m_pWorker = nullptr;
QThread *m_pWorkerThread = nullptr;
};
MainWindow.cpp
#include "MainWindow.h"
#include <QVBoxLayout>
#include <QPushButton>
#include <QWidget>
#include <QDebug>
#include <QThread>
#include "Worker.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
InitCtrl();
qDebug()<<__FUNCTION__<<"mainwindow thread id"<< QThread::currentThreadId();
}
MainWindow::~MainWindow()
{
}
void MainWindow::InitCtrl(void)
{
m_pCenterWidget = new QWidget(this);
m_pStartTaskBtn = new QPushButton(QStringLiteral("Start"),this);
QVBoxLayout *pvertlayout = new QVBoxLayout();
pvertlayout->addWidget(m_pStartTaskBtn);
m_pCenterWidget->setLayout(pvertlayout);
setCentralWidget(m_pCenterWidget);
m_pStartTaskBtn->setCheckable(true);
connect(m_pStartTaskBtn,&QPushButton::clicked,this,&MainWindow::StartTaskBtnSlot);
}
void MainWindow::StartTaskBtnSlot(const bool &checked)
{
if(checked)
{
m_pStartTaskBtn->setText(QStringLiteral("Close"));
m_pWorkerThread = new QThread();
m_pWorker = new Worker();
// move the task object to the thread BEFORE connecting any signal/slots
m_pWorker->moveToThread(m_pWorkerThread);
connect(m_pWorkerThread, SIGNAL(started()), m_pWorker, SLOT(WorkerTaskStartSlot()));
connect(m_pWorker, SIGNAL(WorkertResultSig()), this, SLOT(WorkertResultSlot()));
// automatically delete thread and task object when work is done:
connect(m_pWorkerThread, SIGNAL(finished()), m_pWorker, SLOT(deleteLater()));
connect(m_pWorkerThread, SIGNAL(finished()), m_pWorkerThread, SLOT(deleteLater()));
m_pWorkerThread->start();
}
else
{
m_pStartTaskBtn->setText(QStringLiteral("Start"));
m_pWorkerThread->quit();
m_pWorkerThread->wait();
}
}
void MainWindow::WorkertResultSlot(void)
{
qDebug()<<__FUNCTION__<<"threadid"<<QThread::currentThreadId();
}
Finally, it will output result like this:
MainWindow::MainWindow mainwindow thread id 0x2bf0
Worker::Worker threadid 0x2bf0
Worker::WorkerTaskStartSlot threadid 0x4af0
MainWindow::WorkertResultSlot threadid 0x2bf0
Worker::TimerOutToDoSomethingSlot threadid 0x4af0
Worker::TimerOutToDoSomethingSlot threadid 0x4af0
Worker::TimerOutToDoSomethingSlot threadid 0x4af0
Worker::TimerOutToDoSomethingSlot threadid 0x4af0
Worker::TaskFinished threadid 0x4af0
Worker::TaskFinished stop timer 0x4af0
Worker::~Worker threadid 0x4af0

Qt two or multiple same signals calling slot only once

I'm sending two (or more) same signals, which receives one slot, but it is only called once instead of two times.. What I'm doing wrong?
main.cpp:
#include <QCoreApplication>
#include "app.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
App app;
QMetaObject::invokeMethod(&app, "run", Qt::QueuedConnection);
return a.exec();
}
app.h:
#ifndef APP_H
#define APP_H
#include <QObject>
#include "tcpserver.h"
#include "tcpsocket.h"
class App : public QObject
{
Q_OBJECT
public:
explicit App(QObject *parent = 0);
signals:
public slots:
void run()
{
qDebug() << "run()";
server.server_start(1111);
socket.connectToHost("127.0.0.1", 1111);
socket.write("hello", 5);
socket.write("olleh", 5); // should execute slot two times.
}
private:
TcpServer server;
TcpSocket socket;
};
#endif // APP_H
TcpSocket.h:
#ifndef TCPSOCKET_H
#define TCPSOCKET_H
#include <QTcpSocket>
class TcpSocket : public QTcpSocket
{
Q_OBJECT
public:
explicit TcpSocket(QObject *parent = 0);
signals:
void dataReady(QByteArray data);
public slots:
void readyRead()
{
qDebug() << "Bytes available:" << this.bytesAvailable(); // called only once.
data = this.readAll(); // just for testing.
emit dataReady(data); //
}
void disconnected();
private:
QByteArray data;
};
#endif // TCPSOCKET_H
as you can see, I'm doing two socket.write functions, which should be handled two readyRead slots, but it is called only once. I honestly don't understand what I'm doing wrong.
Regards.

Declaring a signal in Qt script prototype

I tried declaring a signal in a prototype and then connecting it is script funcition for some reason it does not work as I hoped. My code is as follows. Could some one help me in this.
What I expected was, once I called p.setText('New String') in the script code, since setText emits the textChanged signal it should invoke the slot which is catchSignal(text) already connected in the script code.
Prototype header
#ifndef SCRIPTACTION_H
#define SCRIPTACTION_H
#include <QObject>
#include <QtScript>
class ScriptAction : public QObject , public QScriptable
{
Q_OBJECT
public:
ScriptAction(QObject *parent = 0);
signals:
void textChanged(const QString changedString);
};
#endif // SCRIPTACTION_H
Class
#include "scriptaction.h"
#include <QAction>
Q_DECLARE_METATYPE(QAction*)
ScriptAction::ScriptAction(QObject *parent) : QObject(parent)
{
}
Main Class
#include <QApplication>
#include <QDebug>
#include <QAction>
#include "scriptaction.h"
#include <QPushButton>
Q_DECLARE_METATYPE(QAction*)
QScriptValue qAction_Constructor(QScriptContext *ctx, QScriptEngine *eng)
{
qDebug() << "QAction is called";
if(ctx->isCalledAsConstructor())
{
QObject *parent = ctx->argument(0).toQObject();
QAction *action = new QAction("Test",parent);
return eng->newQObject(action, QScriptEngine::ScriptOwnership);
} else {
return QString("invalid call. Use new Constructor");
}
}
int main(int argc, char *argv[])
{
QApplication app(argc,argv);
QScriptEngine engine;
//Evaluating a simaple expresssion
qDebug() << engine.evaluate("1+2").toNumber();
QPushButton button;
QScriptValue buttonScript= engine.newQObject(&button);
engine.globalObject().setProperty("button", buttonScript);
engine.evaluate("button.text ='Hello Text'; button.show()");
//QAction Prototype
ScriptAction qsAction ;
QScriptValue script_proto = engine.newQObject(&qsAction);
engine.setDefaultPrototype(qMetaTypeId<QAction*>(), script_proto);
QScriptValue ctor = engine.newFunction(qAction_Constructor , script_proto);
QScriptValue metaObject = engine.newQMetaObject(&QObject::staticMetaObject, ctor);
engine.globalObject().setProperty("QSAction" , metaObject);
engine.evaluate("var p = new QSAction(button);p.textChanged.connect(catchSignal);");
engine.evaluate("function catchSignal(text) { print ('PROTOTYPE SIGNAL IS CALLED ',text); } p.setText('New String'); " );
return app.exec();
}
I got rid of the issue, and now I see the signal is being triggered and slot is called properly.
All I did was moving the code to a separate script file and start using the QScriptDebugger to see its output. Then I figured there was an error and the code is edited to work.
Anyone who wants an example prototype class, this will hopefully be a good guideline.

Connecting signals and slots in a QTextEdit subclass?

I derived a class from QTextEdit and use it as a "logbook". I equipped it with a slot to receive log-messages.
class CLogbook : public QTextEdit
{
Q_OBJECT;
public:
void log(QString msg) {append(msg)};
public slots:
void recvLogSignal(const QString message)
{
append("hallo");
std::cout << "signal received.\n";
log(message);
}
};
another class then emits a signal like this:
// in the header
signals:
void logMessage(const QString);
// in the implementation
emit logMessage("qt is cute");
std::cout << "if you can read this the logMessage was emitted\n";
and also i connect the signal to the slot
connect(tableeditor, SIGNAL(logMessage(const QString)), logbook, SLOT(recvLogSignal(const QString)));
However the message is never shown in the "logbook". What am i missing here?
SOLVED: The connect method was called after emitting the signal :-(
It is hard to see exactly what is wrong with your implementation without a full example. Sometimes signals or slots will fail if an object goes out of scope if it isn't initialized on the heap.
Another way that it could fail is if your QApplication hasn't reached the exec() call.
I haven't experimented with using const in signal and slot calls, and I haven't seen it in any examples before, so that could be causing the problem; but it seems to work fine in the example below.
Working Example With a Derived Class of QTextEdit
Here is a simple example I put together that does some basic logging with a push button and a line edit.
Here is the header:
#ifndef WIDGET_H
#define WIDGET_H
#include <QtGui/QWidget>
//#include <QTextEdit>
#include "clogbook.h"
#include <QLineEdit>
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget() {}
public slots:
void on_pushButton();
void on_lineEditReturn();
private:
CLogBook * text_edit_log;
QLineEdit * line_edit;
};
#endif // WIDGET_H
Here is the source:
#include "widget.h"
#include <QBoxLayout>
#include <QPushButton>
#include <QTimer>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
QBoxLayout * box_layout = new QBoxLayout(QBoxLayout::TopToBottom);
text_edit_log = new CLogBook;
line_edit = new QLineEdit("Type Here and press Enter.");
QPushButton * push_button = new QPushButton("Click to Add To Log");
text_edit_log->setText("My Log Book");
box_layout->addWidget(text_edit_log);
box_layout->addWidget(line_edit);
box_layout->addWidget(push_button);
this->setLayout(box_layout);
QObject::connect(push_button, SIGNAL(clicked()), this, SLOT(on_pushButton()));
QObject::connect(line_edit, SIGNAL(returnPressed()), this, SLOT(on_lineEditReturn()));
}
void Widget::on_pushButton()
{
// text_edit_log->append("Push Button Logging Test");
text_edit_log->recvLogSignal("Push button test.");
}
void Widget::on_lineEditReturn()
{
// text_edit_log->append(line_edit->text());
text_edit_log->recvLogSignal(QString("LineEdit: ") + line_edit->text() );
line_edit->clear();
}
And here is the main:
#include <QtGui/QApplication>
#include "widget.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
And here is the CLogBook class:
#ifndef CLOGBOOK_H
#define CLOGBOOK_H
#include <QTextEdit>
#include <iostream>
class CLogBook : public QTextEdit
{
Q_OBJECT
public:
explicit CLogBook(QWidget *parent = 0) : QTextEdit(parent) { }
void log (QString msg) { append(msg); }
public slots:
void recvLogSignal(const QString message)
{
append("hallo");
std::cout << "signal received.\n" << std::endl;
log(message);
}
};
#endif // CLOGBOOK_H

Resources