Can we emit a signal from a public slot - c++

class MyMainWindow:public QMainWindow {
public:
MyWindow* myWindow() { return myWindow ;}
private:
MyWindow* myWindow;
};
class MyWindow:public Qobject {
private slot:
void mySlot();
};
class MyWindow2: class QWidget {
public slot:
void refreshClick();
signals:
signal1();
};
MyWindow2::MyWindow2(QMainWindow* parent) {
QPushButton* refresh;
QObject::connect(refresh,SIGNAL(clicked()), this, SLOT(refreshClicked()));
if(parent) {
QObject::connect(this,SIGNAL(signal1),parent->myWindow(),SLOT(mySlot));
}
}
void MyWindow2::refreshClicked(){
emit signal1();
}
I want to know if it is legal to emit signal1 from slot refreshClicked and also are there any cons of emitting a signal from within a slot

Yes, it is perfectly ok. But if your only goal is to "forward" a signal, you can also connect your "incoming" signal directly to the signal you are emmitting. eg.:
connect(advisor , SIGNAL(hasAdvice()),
this , SIGNAL(executeAdvice())
)
But keep in mind that this does not always benefit the extendablity of your code.

Related

Qt Slot and signal are not connected: No such signal

I am trying to deal with slots and signals in Qt, for this I am trying to do the following:
The MyTestClass class should send a signal to the ReceiverClass class, the code:
mytestclass.h
class MyTestClass : public QObject
{
Q_OBJECT
public:
MyTestClass();
void makeSignal();
signals:
void sendSignal();
};
mytestclass.cpp
MyTestClass::MyTestClass()
{
}
void MyTestClass::makeSignal()
{
emit sendSignal();
}
reseiverclass.h
class ReceiverClass : public QObject
{
Q_OBJECT
public:
ReceiverClass();
public slots:
void receiverSlot();
};
reseiverclass.cpp
ReceiverClass::ReceiverClass()
{
}
void ReceiverClass::receiverSlot()
{
qInfo() << "receiverSlot called!\n";
}
main.cpp
...
MyTestClass testObj;
ReceiverClass receiverObj;
QObject::connect(&testObj, SIGNAL(&testObj::sendSignal()), &receiverObj, SLOT(&receiverObj::receiverSlot));
testObj.makeSignal();
...
However, I encounter such an error.
Why doesn't Qt see the signal?
QObject::connect: No such signal MyTestClass::&testObj::sendSignal() in ..\testQtProject\main.cpp:15
QObject::connect(&testObj, SIGNAL(&testObj::sendSignal()), &receiverObj, SLOT(&receiverObj::receiverSlot));
You are mixing the syntax of the 2 methods for connecting signal and slots in Qt, either use :
QObject::connect(&testObj, SIGNAL(sendSignal()), &receiverObj, SLOT(receiverSlot()));
or
QObject::connect(&testObj, &testObj::sendSignal, &receiverObj, &receiverObj::receiverSlot);
For more informations, look at https://doc.qt.io/qt-5/signalsandslots.html and https://wiki.qt.io/New_Signal_Slot_Syntax

Serialport in a separate QThread

I'd like to insert the serial port in a separate QThread, but the application crashes. I wrote the following C++ classes
Worker.h
class Worker : public QObject
{
Q_OBJECT
public:
explicit Worker(QObject *parent = 0);
signals:
void finished();
void error(QString err);
public slots:
void process();
};
class WorkerInterface : public QObject
{
Q_OBJECT
public:
explicit WorkerInterface(QObject *parent = nullptr);
~WorkerInterface();
serialport *readSerialPort();
signals:
void threadStoppedChanged();
public slots:
void errorString(QString errorMsg);
void stopThread();
private:
QThread m_thread;
serialPort *m_serial;
};
Worker::Worker(QObject *parent)
: QObject(parent)
{
}
void Worker::process()
{
emit finished();
}
Worker.cpp
WorkerInterface::WorkerInterface(QObject *parent)
: QObject(parent)
, m_thread(this)
{
serialPort::serialPortMaster = new serialPort(nullptr);
m_serial = serialPort::serialPortMaster;
serialPort::serialPortMaster->moveToThread(&m_thread);
connect(&m_thread, SIGNAL(started()),serialPort::serialPortMaster, SLOT(Init()));
m_thread.start();
}
WorkerInterface::~WorkerInterface()
{
m_thread.quit();
m_thread.wait(1000);
if (!m_thread.isFinished())
m_thread.terminate();
}
void WorkerInterface::errorString(QString errorMsg)
{
qDebug() << "error" << errorMsg;
}
void WorkerInterface::stopThread()
{
m_thread.quit();
m_thread.wait(1000);
if (!m_thread.isFinished())
m_thread.terminate();
emit threadStoppedChanged();
}
serialPort* WorkerInterface::readSerialPort()
{
return(m_serialPort);
}
In the main.cpp I wrote the following code:
WorkerInterface workerInterface;
engine.rootContext()->setContextProperty("newserial", workerInterface.readSerialPort());
QQmlComponent component(&engine,QUrl(QStringLiteral("qrc:/Pages/Content/Qml/main.qml")));
QObject *qmlObject = component.create();
When the code arrives at the last instruction in main.cpp, the application crashes and in the QT creator console there is the following messages:
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QSerialPort(0xee18c0), parent's thread is QThread(0xc8d8b0), current thread is QThread(0x7fffffffdc60)
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QSerialPort(0xee18c0), parent's thread is QThread(0xc8d8b0), current thread is QThread(0x7fffffffdc60)
QQmlEngine: Illegal attempt to connect to serialPort(0xee1710) that is in a different thread than the QML engine QQmlApplicationEngine(0x7fffffffdc30.
Could someone help me to solve the crash?
Many thanks in advance.
Assuming that you have device which responds with text, the best and simplest way to do it is something like this:
class IODevLineReader
{
Q_OBJECT
public:
explicit IODevLineReader(QObject *parent);
public signals:
void lineWasReceived(const QString &line);
public slots:
void onReadyRead() {
QIODevice *dev = qobject_cast<QIODevice *>(sender());
while (dev && dev->canReadLine()) {
auto lineBytes = dev->readLine();
emit lineWasReceived(lineBytes);
}
}
};
Just connect QSerialPort::readyRead() to IODevLineReader::onReadyRead() and connect some slot to IODevLineReader::lineWasReceived() signal and you are done without use of threads.
And if you still insist to use thread, just use same object tree and move it to specified thread.

Qt GUI doesn't work with std::thread as I expect

The core of my project is independent of GUI framework that's why I prefer std::thread. But Qt gives me an error when thread is using.
The inferior stopped because it received a signal from the operating system.
Signal name: SIGSEGV
Signal meaning: Segmentation fault
//MainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <thread>
#include <mutex>
#include <QMainWindow>
namespace Ui { class MainWindow; }
struct Observer
{
virtual void notify() = 0;
};
class Core
{
public:
std::thread *run()
{
std::thread thread(&Core::runP, this);
thread.detach();
return &thread;
}
void setObserver(Observer *observer) { _observer = observer; }
int ii() const { return _ii; }
void nextIi() { _ii++; }
void lock() { _mutex.lock(); }
bool tryLock() { return _mutex.try_lock(); }
void unlock() { _mutex.unlock(); }
private:
void runP()
{
for (int i = 1; i <= 1000; i++) {
if (i % 10 == 0) {
lock();
nextIi();
unlock();
notify();
}
}
}
void notify() { _observer->notify(); } //!!!
Observer *_observer;
int _ii;
std::mutex _mutex;
};
struct MwObserver : public Observer
{
explicit MwObserver(struct MainWindow *mainWindow) { _mainWindow = mainWindow; }
virtual void notify();
MainWindow *_mainWindow;
};
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow() { delete _ui; }
void upd();
public slots:
void run() { _core.run(); }
private:
Ui::MainWindow *_ui;
MwObserver _observer;
Core _core;
};
inline void MwObserver::notify() { _mainWindow->upd(); }
#endif
-
//MainWindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
_ui(new Ui::MainWindow),
_observer(this)
{
_ui->setupUi(this);
connect(_ui->pushButtonRun, SIGNAL(clicked(bool)), this, SLOT(run()));
}
void MainWindow::upd()
{
_core.lock();
setWindowTitle(QString::number(_core.ii()));
_core.unlock();
}
There are multiple problems here, first and most obvious was already noted by perencia. You are returning a pointer to stack variable. In c++ terms it's unacceptable.
Secondly. The crash comes from not using std::thread, but from race condition. The Qt event loop does not know about you mutex, so your setWindowTitle call is introducing a race, that leads to crash.
You need to use QMetaObject::invokeMethod to post function to the Qts event loop.
Example:
change
inline void MwObserver::notify() { _mainWindow->upd(); }
to
inline void MwObserver::notify() {
if(!QMetaObject::invokeMethod(_mainWindow, "upd", Qt::QueuedConnection))
std::cerr << " Failed to invoke method" << std::endl;
}
additional includes may apply
This updates the GUI from a thread different then the GUI thread! Which is not allowed.
Why not to use QThread and a signal/slot mechanism to update your window title. The Qt framework does the thread switching automatically.
class Core : public QObject
{
Q_OBJECT
public:
explicit Core(QObject * parent = 0) : QObject(parent) {}
signals:
void notify();
public slots:
void nextIi() { _ii++; }
void runP()
{
for (int i = 1; i <= 1000; i++) {
if (i % 10 == 0) {
nextIi();
notify();
}
}
}
private:
Q_DISABLE_COPY(Core);
int _ii;
};
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
void run() {_th.start();}
void upd(int ii) {setWindowTitle(QString::number(ii));}
private:
Ui::MainWindow *_ui;
Core _core;
QThread _th;
};
//MainWindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
_ui(new Ui::MainWindow),
_observer(this)
{
_ui->setupUi(this);
connect(_ui->pushButtonRun, SIGNAL(clicked(bool)), this, SLOT(run()));
connect(&_core, SIGNAL(notify(int)), this, SLOT(upd(int)));
_core.moveToThread(&_th);
}
MainWindow::~MainWindow()
{
delete _ui;
_th.quit();
_th.wait(1000);
}
You are creating thread on the stack and returning a pointer to that. After run() that pointer is no longer valid.
Aside from returning pointer to stack variable and updating GUI from thread object that is not known for QT. I don't see from your code, where you set up _observer member of Core class. There is no setObserver call for _core member of MainWindow class.
So consructor of MainWindow class calls consructor of _core member, but after that _core._observer contains garbage. I think this is the cause of your Segmentaion Fault in call of notify method of Core class.
The answers to all the problems have already been given, let me summarize.
The program crash has nothing to do with the threading, The problem is that the _observer in the _core member of MainWindowis not set. A call to setObserver must be added.
explicit MainWindow( QWidget *parent = nullptr ) :
QMainWindow( parent ),
_observer( this )
{
_core.setObserver( &_observer );
}
This will lead to the next problem, that the observer actually calls the udp message from another thread, causing a UI update in a different thread context. To solve this, it is easiest to use Qt's Qt::QueuedConnection. To enable this we must make upt() a slot.
public slots:
void run();
void upd();
Then we can either call it using QMetaObject::invokeMethod in
inline void MwObserver::notify()
{
QMetaObject::invokeMethod( _mainWindow, "upd", Qt::QueuedConnection );
}
or use a signal / slot connection by deriving MwObserver from QObject, giving it a signal, and connect that signal to the upd slot and raising the signal in notify.
struct MwObserver
: public QObject
, public Observer
{
Q_OBJECT;
signals:
void sigUpd();
public:
explicit MwObserver( MainWindow *mainWindow );
virtual void notify()
MainWindow *_mainWindow;
};
void MwObserver::notify()
{
sigUpd();
}
MwObserver::MwObserver( MainWindow *mainWindow )
{
_mainWindow = mainWindow;
connect( this, SIGNAL(sigUpd()), _mainWindow, SLOT(upd()) )
}
Disclaimer: I haven't used Qt in some time but with X/XMotif on Linux/UNIX the GUI MUST run in the 'main-thread', not spawned threads. Maybe this applies to your situation. Just a thought, have your GUI code run in the main-thread.
The best approach is to wrap pure C++ code with QObejct instance and fire signals when this objects receive some notification from pure C++ code.
SO in your case:
class MwObserver : public QObject, public Observer
{
Q_OBJECT
public:
explicit MwObserver(QObject *parent)
: QObject(parent)
{}
signals:
void SomeEvent();
protected:
// Observer
void notify() {
emit SomeEvent();
}
};
Now MainWindow should connect some slot to signal provided this way and everything should work out of the box (Qt will do thread jumping behind the scenes).
In your code form comment the crash is caused by invalid use of temporary object. This is INVALID C++ code no mater what kind of object is returned:
std::thread *run()
{
std::thread thread(&Core::runP, this);
thread.detach();
return &thread;
}
You cant return a pointer to local object of the function method, since this object becomes invalid immediately when you return a function. This is basic C++ knowledge.

Emitting signals from class, if transition in QStateMachine was successful

My problem is the following: I need to create class, which contains QStateMachine instance. This class should have slots through which you could "ask" state machine to make transition to another state. And if transition was successful, my class should emit signal about it. How would I implement this? Class should have ability to emit certain signals according to certain slot invoke.
Here is a small example of class:
class MyClass : public QObject
{
Q_OBJECT
public:
explicit MyClass(QObject *parent = 0)
{
mStateMachine = new QStateMachine(this);
QState *s1 = new QState(mStateMachine);
QState *s2 = new QState(mStateMachine);
QState *s3 = new QState(mStateMachine);
s1->addTransition(); // Transition to s2
s2->addTransition(); // Transition to s3
s3->addTransition(); // Transition to s1
mStateMachine->setInitialState(s1);
mStateMachine->start();
}
signals:
toS1();
toS2();
toS3();
public slots:
slotToS1()
{
/* post event to state machine about
transition to state s1,
if transition was successful,
then emit toS1() signal. */
};
slotToS2(){ /* Similar to slotToS1 */};
slotToS3(){ /* Similar to slotToS1 */};
private:
QStateMachine *mStateMachine;
}
I would be very grateful for your help!
UPD:
The slots are representing defferent kinds of transitions, so that outer class (that will be using MyClass) could 'ask' for some transition. So, the slot send event or signal to state machine, it looks on event or signal and (if in right state) makes this transition. And I want to notify outer class with certain signal, that asked before slot (transition) was made successfuly.
To transition on a slot call, you need to somehow bind the slot to a QAbstractTransition. There are two ways of doing it:
Use a QEventTransition and send a relevant event to trigger it.
Use a QSignalTransition and use an internal signal to trigger it.
To emit signals on state transitions, you can connect the QAbstractTransition::triggered or QState::entered or QState::exited signals to other signals. Remember, in Qt a connection target can be either a slot or a signal.
Thus, using signal transitions:
class MyClass : public QObject
{
Q_OBJECT
QStateMachine machine;
QState s1, s2;
Q_SIGNAL void s_go_s1_s2();
Q_SIGNAL void s_go_s2_s1();
public:
Q_SIGNAL void transitioned_s1_s2();
Q_SIGNAL void transitioned_s2_s1();
Q_SLOT void go_s2_s1() { emit s_go_s2_s1(); }
Q_SLOT void go_s1_s2() { emit s_go_s1_s2(); }
explicit MyClass(QObject *parent = 0) : QObject(parent),
s1(&machine), s2(&machine) {
auto s1_s2 = s1.addTransition(this, SIGNAL(s_go_s1_s2()), &s2);
auto s2_s1 = s2.addTransition(this, SIGNAL(s_go_s2_s1()), &s1);
machine.setInitialState(&s1);
machine.start();
connect(s1_s2, &QAbstractTransition::triggered, this, &MyClass:: transitioned_s1_s2);
connect(s2_s1, &QAbstractTransition::triggered, this, &MyClass:: transitioned_s2_s1);
}
}
Using event transitions is a bit harder, since the events you're using must be cloneable by the state machine. The core module's state machine only knows how to clone the None and Timer events - see its cloneEvent implementation.
The widgets module adds support for various GUI/Widgets events - see the cloneEvent implementation there. You could, in a pinch, use such GUI events for your own purposes - after all, they are sent to a plain QObject that doesn't interpret them in a special way.
You can provide your own cloneEvent implementation that links with the others.
#include <private/qstatemachine_p.h>
class MyClass : public QObject
{
Q_OBJECT
QStateMachine machine;
QState s1, s2;
QEvent e_s1_s2, e_s2_s1;
QEventTransition s1_s2, s2_s1;
public:
Q_SIGNAL void transitioned_s1_s2();
Q_SIGNAL void transitioned_s2_s1();
Q_SLOT void go_s2_s1() { QCoreApplication::sendEvent(this, &e_s2_s1); }
Q_SLOT void go_s1_s2() { QCoreApplication::sendEvent(this, &e_s1_s2); }
explicit MyClass(QObject *parent = 0) : QObject(parent),
s1(&machine), s2(&machine),
e_s1_s2((QEvent::Type)(QEvent::User + 1)),
e_s2_s1((QEvent::Type)(QEvent::User + 2)),
s1_s2(this, e_s1_s2.type()),
s2_s1(this, e_s2_s1.type()) {
s1_s2.setTargetState(&s2);
s2_s1.setTargetState(&s1);
s1.addTransition(&s1_s2);
s2.addTransition(&s2_s1);
machine.setInitialState(&s1);
machine.start();
connect(&s1_s2, &QAbstractTransition::triggered, this, &MyClass::transitioned_s1_s2);
connect(&s2_s1, &QAbstractTransition::triggered, this, &MyClass::transitioned_s2_s1);
}
}
static const QStateMachinePrivate::Handler * last_handler = 0;
static QEvent * cloneEvent(QEvent * e) {
if (e->type() >= QEvent::User && e->type() < QEvent::User+100) {
return new QEvent(e->type());
return last_handler->cloneEvent(e);
}
const QStateMachinePrivate::Handler our_handler = {
cloneEvent
};
void registerHandler() {
last_handler = QStateMachinePrivate::handler;
QStateMachinePrivate::handler = &our_handler;
}
Q_CONSTRUCTOR_FUNCTION(registerHandler())
void unregisterHandler() {
QStateMachinePrivate::handler = last_handler;
}
Q_DESTRUCTOR_FUNCTION(unregisterHandler())
I have had the same problem in the past and I have found the easiest way was to inherit from QState with your own QState class and implement 2 methods called QState::onEntry(QEvent * event) and QState::onExit(QEvent * event).
This way you are able to emit any signal you like when you exit and when you enter a new state.
Here is and example:
file mystate.h
#include <QState>
class MyState : public QState
{
Q_OBJECT
public:
explicit MyState(qint32 stateId, QState * parent = 0);
protected:
void onEntry(QEvent * event);
void onExit(QEvent * event);
signals:
void exit(qint32 stateId);
void enter(qint32 stateId);
private:
qint32 stateId;
};
And file mystate.cpp
#include "mystate.h"
MyState::MyState(qint32 stateId, QState *parent)
{
this->stateId = stateId;
}
void MyState::onEntry(QEvent *event)
{
emit enter(stateId);
}
void MyState::onExit(QEvent *event)
{
emit (exit(stateId));
}

Qt Signals and Slots Confusion

I have been reading about Qt signals and slots and I am trying to get this to work, but until now without success. I hope someone can point me in the right direction.
I have two files, homeCommand.cpp and messagelogcommand.cpp. I have a QPlainTextEdit object in messagelogcommand.cpp that I want to update from homeCommand.cpp.
How can I do this using signals and slots? My signal is being called, as my QDebug is being printed out once a second, however the widget does not update.
This is what I am trying to do:
In MessageLogCommand.h
class MessageLogCommand : public QWidget
{
Q_OBJECT
public:
explicit MessageLogCommand(QWidget *parent = 0);
QLabel *homeLabel;
QPlainTextEdit *messageLog;
public Q_SLOTS:
void updateWidgets(const QString &text);
};
homeCommand.h
class homeCommand : public QWidget
{
Q_OBJECT
Q_SIGNALS:
void textChanged(const QString &text);
public:
explicit homeCommand(QWidget *parent = 0);
public slots:
void run(void);
void getHealthStatusPacket(void);
homeCommand.cpp
homeCommand::homeCommand(QWidget *parent) : QWidget(parent)
{
...
//Timer
QTimer *timer = new QTimer(this);
timer->setSingleShot(false);
connect(timer, SIGNAL(timeout()), this, SLOT(run()));
timer->start(1000);
setLayout(layout);
}
void homeCommand::run(void)
{
getHealthStatusPacket();
}
void homeCommand::getHealthStatusPacket(void)
{
...
Q_EMIT textChanged("ZOMG");
}
In MessageLogCommand.cpp
MessageLogCommand::MessageLogCommand(QWidget *parent) : QWidget(parent)
{
QGridLayout *layout = new QGridLayout;
QWidget::setFixedHeight(600);
//Sub-system Label
homeLabel = new QLabel("GSS Message Log");
QFont subsystemFont = homeLabel->font();
subsystemFont.setPointSize(12);
subsystemFont.setBold(true);
homeLabel->setFont(subsystemFont);
layout->addWidget(homeLabel, 0, 0);
//Event Log
messageLog = new QPlainTextEdit();
messageLog->setFixedHeight(500);
messageLog->setFixedWidth(600);
layout->addWidget(messageLog, 2,0);
setLayout(layout);
}
void MessageLogCommand::updateWidgets(const QString &text)
{
qDebug() << "Here";
messageLog->appendPlainText(text);
}
In main.cpp
MessageLogCommand s;
homeCommand m;
QObject::connect(&m, SIGNAL(textChanged(QString)), &s, SLOT(updateWidgets(QString)));
A very basic example is:
class MainClass:public QObject //class must be derived from QObject!
{
Q_OBJECT //this macro must be in the class definition
//so the moc compiler can generate the necessary glue code
public:
void doSomething() {
...
Q_EMIT textChanged(someText);
}
Q_SIGNALS:
void textChanged(const QString &text);
};
class SubClass:public QObject
{
Q_OBJECT
public Q_SLOTS:
void onTextChanged(const QString &text) { //do not inline
//do something
}
};
int main()
{
QApplication a;
MainClass m;
SubClass s;
QObject::connect(&m, SIGNAL(textChanged(QString)),
&s, SLOT(onTextChanged(QString))); //const and & are removed from
//the arguments
return a.exec(); //run the event loop
}
So, there are 2 things important:
1. Signals and slots must be declared in a class derived from QObject
2. The classes containing signals and slots declarations must add the Q_OBJECT macro to the class declaration
To keep it simple for you: always declare your classes containing signals or slots in a header file (never in a .cpp file).
A very good starting point for signals and slots is: http://woboq.com/blog/how-qt-signals-slots-work.html but also the official Qt doc does it: http://qt-project.org/doc/qt-4.8/signalsandslots.html
Basically what happens: you declare some special methods (signals and slots), at the compilation phase Qt generates extra CPP files which take care of your methods (moc) then everything is compiled and linked together and at the end when Qt or someone else emits a signal it will go to the corresponding slot.
I try to explain it.
In main.h you should to declare a signal:
signals:
void textChanged(const QString& text);
And in messagelog.h you should to declare a slot:
public slots:
void updateWidgets(const QString& text);
In main.cpp you should emit this signal:
void TheMethod() {
emit this->textChanged("Your text/value");
}
In messagelog.cpp you should get this value:
// Note: Normalized signal/slot signatures drop the consts and references.
connect(&a, SIGNAL(textChanged(QString)), this, SLOT(updateWidgets(QString)));
void updateWidgets(const QString& text) {
messageLog = new QPlainTextEdit();
messageLog->setFixedHeight(500);
messageLog->setFixedWidth(600);
messageLog->setPlainText(text)
layout->addWidget(messageLog, 2,0);
}
I think it should works.
UPDATE:
Complete example: https://dl.dropboxusercontent.com/u/29647980/test.zip