Qt6 Connect Signal to Lambda Function - c++

I'm using a DataRouter class to handle communication with a QSerialPort (and then communicate the results elsewhere). The connected device sends a status package every second or so, and I would like to read it without polling the device. I tried directly using QSerialPort's waitForReadyRead function, but no matter how long I set the wait time, it always timed out. Looking here and here I saw signals can be connected to Lambda functions. Now I'm trying to connect QSerialPort's readyRead signal to a Lambda which calls my on_dataRecieved function but I get the error C2665:"QObject::connect: none of the 3 overloads could convert all of the argument types. Below is an example of what I have:
DataRouter.h
template<class SerialPort>
class DataRouter
{
public:
DataRouter ();
private slots:
on_dataRecieved();
private:
shared_ptr<SerialPort> m_port;
};
DataRouter.cpp
template<class SerialPort>
DataRouter<SerialPort>::DataRouter()
{
m_port = std::make_shared<SerialPort>()
QObject::connect(m_port, &QSerialPort::readyRead, this, [=](){this->on_dataRecieved();})
}
template<class SerialPort>
void DataRouter<SerialPort>::on_dataRecieved()
{
//Do stuff
}

If your "target" is not QObject you need to use the following overload of connect. The problem is that, you are trying to use non-QObject as "context" to determine the lifetime of the connection and that's not possible. To mitigate it you will need to release the connection somehow on DataRouter's destruction; one way is to store what connect() will have returned and call disconnect on it later on.
As for the signal coming from a smart pointer, have you tried this:
connect(m_port->get(), &QSerialPort::readyRead, &DataRouter::on_dataRecieved);

Your m_port is not entity of QSerialPort class, that's why you don't have QSerialPort::readyRead that can be emitted from it. template<class SerialPort> doesn't do what you what, it is just name of templated parameter.
You probably wanted something like this:
DataRouter.h
class DataRouter : QObject
{
public:
DataRouter ();
private slots:
on_dataRecieved();
private:
QSerialPort* m_port;
};
DataRouter.cpp
DataRouter::DataRouter()
{
m_port = new QSerialPort(this);
connect(m_port, &QSerialPort::readyRead, this, &DataRouter::on_dataRecieved);
// or connect(m_port, &QSerialPort::readyRead, this, [this](){this->on_dataRecieved();});
}
void DataRouter::on_dataRecieved()
{
//Do stuff
}
You don't have to wrap Qt classes in smart pointers as long, as you provide parent class for them. Memory freed when parent is destructed.

Related

How can I emit a signal of another instance from _clicked() event?

the runnable project is here:
enter link description here
I sincerely glad to have your detail answers to solve this, but I am still confusing on this issue:
case 1: changing socket_session as a member variable of mainwindow
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
SocketThread* socket_session;
private:
...
But this is not the solution to access setFlag, even after I change the `Form1::on_qpushButton__set_white_level_0_clicked()' function like this:
void Form1::on_qpushButton__set_white_level_0_clicked() {
qDebug() <<"clicked()";
socket_session->setThreadFlag(true);
}
Still it doesn't make sense because form1 instance doesn't have "the" instance of socket_thread which has been instantiated from mainwindow.
There's a solution I think is making another class that includes all instances that I want to use from inside of mainwindow but I don't think that is a good one because I am using thread and accessing a global big instance class that includes all of them to be "shared" is not a good idea for someone like me.
#include <form1.h>
#include <ui_form1.h>
#include "socketthread.h"
Form1::Form1(QWidget *parent) :
QWidget(parent),
ui(new Ui::Form1) {
ui->setupUi(this);
}
Form1::~Form1() {
delete ui;
}
void Form1::on_qpushButton__set_white_level_0_clicked() {
qDebug() <<"clicked()";
socket_session->setThreadFlag(true);
}
enter image description here
I know I am lack of understanding about this but, do I wanna make something nobody does...? I think everyone wants to separate all objects and their methods clearly and communicate via signals or calling functions from delivered object instances...
case 2: ... let me try how you suggested make possible first...
I can read C++ code and overall structure, but I don't know why I have to struggle with this, so please help me, dear Guru.
On socketthread.h :
class SocketThread : public QThread {
Q_OBJECT
public:
QTcpSocket *socket_session;
SocketThread();
~SocketThread(){}
bool connectToServer(QString, int);
void sendData(const char*, int, int);
void run(void);
private:
QString message;
volatile bool threadFlag;
signals:
void changedThreadFlag(void);
void changedMessageStr(void);
void setThreadFlag(bool);
void setMessageStr(QString);
private slots:
void setStr(QString);
void setFlag(bool);
void socketError(QAbstractSocket::SocketError);
};
And its implementation is...
SocketThread::SocketThread() {
socket_session = NULL;
threadFlag = false;
message = "NULL";
connect(this, SIGNAL(setThreadFlag(bool)), this, SLOT(setFlag(bool)));
}
...
void SocketThread::setStr(QString str) {
message = str;
}
void SocketThread::setFlag(bool flag) {
threadFlag = flag;
}
void SocketThread::run() {
while(true) {
if(threadFlag) {
QThread::msleep(100);
qDebug() << message;
} else
break;
}
qDebug() << "loop ended";
}
And I have one form which has a button, and I put a clicked() slot of it like this...
void Form1::on_qpushButton__set_white_level_0_clicked() {
qDebug() <<"clicked()";
--how can I emit the signal of the one of socketthread from here??
}
Now, the mainwindow is like this:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow) {
QString addr_server = "223.194.32.106";
int port = 11000;
SocketThread* socket_session = new SocketThread();
socket_session->connectToServer(addr_server, port);
ui->setupUi(this);
Form1* form1;
form1 = new Form1();
ui->stackedWidget_mainwindow->addWidget(form1);
ui->stackedWidget_mainwindow->setCurrentWidget(form1);
socket_session->run();
...
I just simply want to emit the signal setThreadFlag of the socketthread from inside of QPushbutton_clicked() slot.
Once the socket_session->run() started, I need to change the threadFlag by clicking the button by emitting setThreadFlag() of one's from the running thread. And I just stuck in here.
Does it possible even?
Or am I doing this all wrong from the beginning?
As mentioned in this post:
"Emitting a signal" == "calling a function"
So all you really have to do is call the signal function, and all connected slots should be called.
This of course means that the Form1 object needs a pointer to the thread object, i.e. it needs a copy of socket_session. Then you can simply call the signal on the object
socket_session->setThreadFlag(your_flag);
Of course, if the Form1 have a copy of the socket_session pointer, it might as well call setFlag directly, if it was public.
I just simply want to emit the signal setThreadFlag of the socketthread from inside of QPushbutton_clicked() slot.
No signal is needed – just call the function.
void Form1::on_qpushButton__set_white_level_0_clicked() {
qDebug() <<"clicked()";
// --how can I emit the signal of the one of socketthread from here??
// E.g. this way:
socket_session->setThreadFlag(true);
}
To make this possible, another fix is needed:
socket_session is a local variable in OP's exposed code.
To make it "persistent", it has to become e.g. a member variable.
So, the constructor MainWindow::MainWindow() has to be changed:
// Nope: SocketThread* socket_session = new SocketThread();
// Instead:
socket_session = new SocketThread();
and SocketThread* socket_session; has to be added to member variables of class MainWindow.
To make it accessible in Form1, it has to be passed to Form1 as well.
This could be done e.g. by making it a member variable in Form1 also which is initialized with a constructor argument (or set from MainWindow afterwards).
(I must admit that I never have used the Qt UI builder QtDesigner but build all my UIs by C++ code exclusively.)
But, now, another fix is necessary:
volatile doesn't make a variable suitable for interthread communication.
(This was used in ancient times before multi-threading started to be supported by C++11.)
However, this is wrong: Is volatile useful with threads?
An appropriate fix would be to use std::atomic instead:
// Wrong for interthread-com.
//volatile bool threadFlag;
// Correct:
std::atomic<bool> threadFlag; // #include <atomic> needed
FYI: SO: Multithreading program stuck in optimized mode but runs normally in -O0
And, finally, in SocketThread::SocketThread():
connect(this, SIGNAL(setThreadFlag(bool)), this, SLOT(setFlag(bool)));
is not necessary in this case.
SocketThread::setThreadFlag() could call SocketThread::setFlag() directly, or even write threadFlag itself:
void setThreadFlag(bool flag) { threadFlag = flag; }
As I (recommended to) make threadFlag atomic, it can be accessed from any thread without causing a data race.
Update:
After OP has updated the question:
I just simply want to emit the signal setThreadFlag of the socketthread from inside of QPushbutton_clicked() slot.
The button (created from UI Form1) can be connected in the MainWindow as well (without using any method of Form1):
QObject::connect(form1->button1, &QPushButton::clicked,
socket_session, &SocketThread::setThreadFlag,
Qt::QueuedConnection);
Notes:
About form1->button1, I'm not quite sure.
I noticed that widgets in UI generated forms can be accessed this way but I don't know the exact details (as I never used the Qt UI builder on my own).
I used the Qt5 style of QObject::connect().
This is what I would recommend in any case.
The Qt5 style is verified at compile time. –
Wrong connections are detected by the C++ type checking.
Additionally, any function with matching signature can be used – no explicit exposure of slots is anymore necessary.
Even conversion of non-matching signature or adding additional parameters becomes possible by using C++ lambdas which are supported as well.
Qt: Differences between String-Based and Functor-Based Connections
It is possible to connect signals and slots of distinct threads.
I used Qt::QueuedConnection to remark this as interthread communication.
(However, I roughly remember that Qt might be able to detect it itself.
See the doc. for Qt::AutoConnection which is the default.
Further reading: Qt: Signals & Slots
Btw. using the Qt signals for inter-thread communication would exclude the necissity to make SocketThread::threadFlag() atomic. It could become a simple plain bool threadFlag; instead. The slot SocketThread::setThreadFlag() is called in the Qt event loop of QThread, in this case.

Pass QMetaMethod as parameter to a function that uses the new QObject::connect syntax

I want to kinda build a wrapper around QObject's connect using the new syntax that has type check at compilation time.
The main idea would be: "hey listener, connect this object's slots to my newData signal"
void Listener::_addClient(const QObject *object, const QMetaMethod& slot)
{
connect(this, &Listener::newData, object, slot);
}
And some Client class would simply do:
Listener myListener;
myListener._addClient(this, &Client::mySlot);
This of course does not compile.
Since all Listener objects will be owned by a manager class, I cannot access them directly, so its not possible to do the traditional connect.
How can I build a wrapper for this connect so I can assure the type check at compilation time?
You might use template:
template <typename Receiver, typename Slot>
void Listener::_addClient(const Receiver *object, const Slot& slot)
{
connect(this, &Listener::newData, object, slot);
}
I could not make Jarod42 solution work because I needed access to protected properties and the method needed to be public.
I ended up proceeding as follow
void Listener::_addClient(const QObject *receiver, const char *slot)
{
connect(this, SIGNAL(newData()), receiver, slot);
}
calling like so
Listener myListener;
myListener._addClient(this, SLOT(mySlot()));
It might not be the pretiest way to proceed but it works.

How to pass a signal as function parameter?

So i am looking to make our own generic inherited checkbox class that will be able to take in some values in its constructor and pop out a widget that is fully connected to our model in the manner we need.
Currently we do something like this within our view
connect(checkboxWidget, &QCheckbox::Clicked, this, &VMyView::Signal);
Which emits the Signal from VMyView when the checkbox is clicked.
If i wanted to pass that signal as a parameter into my new inherited class to be hooked up in its own connect statement, how would I do so?
Research has shown me i can pass a const char* but i get compilation errors that the signal/slot do not match.
Example
CheckBox(View myView, const char* signal)
{
connect(this, &QCheckBox::Clicked, myView, signal);
}
Returns an error that Signal and slot arguments are not compatible. Ive also tried SIGNAL(signal) with the same result.
The solution ended up being fairly simple in the end
Instead of using this from within my View
connect(pCheckbox, &QCheckBox::clicked, this, &MyView::Signal);
I use
connect(this, &QCheckBox::clicked, View, signal);
Where signal and comes into my function via a function pointer
MyCheckBox::MyCheckBox(QWidget* parent, MyView* View, void(MyView::*signal)(bool))
The key takeaway is
void(MyView::*signal)(bool)
is equal too
&MyView::Signal
I think the major issue here is that signals are not static member functions. Thus they require a pointer to an instance of the class to be called correctly. So you cannot just pass in things like &VMyView::Signal, as there's no corresponding this pointer attached to the function. (This is why most of the QObject::connect() overloads require an instance to the sender/receiver objects.)
One way to solve this is to create a function object, which contains both the member function pointer and the pointer to the object on which to call it. This can be passed to the QObject::connect() function just fine.
Here's an example:
// objects.h
#include <QtCore>
class Receiver : public QObject
{
Q_OBJECT
public:
Receiver( QObject *parent = nullptr)
: QObject(parent)
{
}
~Receiver() { }
signals:
void sig(void);
};
class Sender : public QObject
{
Q_OBJECT
public:
Sender(std::function<void(void)> &bound_signal, QObject *parent = nullptr)
: QObject(parent)
{
// automatically emit `Sender::sig` on a timer, for testing.
timer = new QTimer(this);
timer->setInterval(1000);
QObject::connect(timer, &QTimer::timeout, this, &Sender::sig);
QObject::connect(this, &Sender::sig, bound_signal);
timer->start();
}
~Sender() { }
signals:
void sig(void);
private:
QTimer *timer;
};
And then a main function:
// main.cc
#include <QtCore>
#include "objects.h"
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
Receiver receiver; // object to receive the signal
// Bind the receiver's signal to the instance of the class
std::function<void(void)> signal = std::bind(&Receiver::sig, &receiver);
// Create a Sender, which will connect its own signal to the
// given bound signal
Sender sender(signal);
QObject::connect(&receiver, &Receiver::sig,
[]() -> void { qDebug() << "received"; });
return app.exec();
}
So, in your case, the Receiver and its signal would be replaced by VMyView and the signals you want to chain, and Sender would be the custom checkbox class you've implemented. Then in the constructor of the checkbox class, connect whatever signals you want to the given bound signals. You can also pass in a list of bound signals, e.g., std::list<std::function<void(void)>> &bound_signals.
I have to say, though, I'm not sure what this buys you. You'll need to write the connection logic somewhere, and I don't see why it needs to be in the constructor of the checkbox class. Wherever the checkbox and the VMyView class are created and used, that seems like a better place to put the connection code. It's more obvious, less convoluted, and there's better separation of concerns. The checkbox class shouldn't have to know or care what signals/slots its connected to. The application logic (i.e., where the objects are used) should define how the objects interact with one another.

How to connect signal and slot without using connect function?

Is there a way to connect signal and slot without using connect function?
If a way exists, please give some examples.
Nope, there is no other way, not in the public API at least. In Qt4 there is only the connect() function with the SIGNAL() and SLOT macro().
In Qt5 you have another, type-safe connection syntax, but it still uses the connect() function. And in QML you can use "attached handlers" - onSignal: doStuff() - but that's just for QML.
There is a way to use the meta-call interface to avoid using the connect() function. Depending on what you precisely need to do though this may not be the solution you are looking for, or it may be.
You essentially define a callback slot function in your QOBJECT class with a certain syntax and let the MOC sort the 'connection' out.
So say you wanted to use:
connect(ui->actionButton, SIGNAL(triggered()), this, SLOT(someCallbackSlot()));
but without having to use the callback function...
You can do it implicitly with a particular syntax of a member function in the QOBJECT who receives the signal:
class MyQtObj : public QWidget
{
QObject
private slots:
void on_actionButton_triggered();
}
Where on_actionButton_triggered is the functional equivalent of someCallbackSlot(), actionButton is the name of the button/action/signal emitter and triggered() is the signal emitted.
So any of these functions are valid providing the signal emitter is correct:
void on_minimizedButton_clicked();
void on_closeButton_released();
etc
When you run the Qt Meta-Object-Compiler and generate your moc_.cpp file of this class there will be a function called qt_static_metacall; this contains a switch statement that looks like :
void MyQtObj::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
MyQtObj*_t = static_cast<MyQtObj*>(_o);
Q_UNUSED(_t)
switch (_id) {
case 0: _t->on_actionButton_triggered(); break;
default: ;
}
}
}
If you put a break point in this and trigger your action/button/signal you should see your function get executed.
I'm not too sure of the details of how this works though and I noticed it when I used this frame-less Qt window code and have now adopted it in my own Qt C++ projects.

When subclassing QTcpServer, how can I delay emitting the newConnection() signal?

I want to create an SSL server, so I subclass QTcpServer and I override incomingConnection(), where I create a QSslSocket, set its descriptor, and call QSslSocket::startServerEncryption. At this point I need to wait for QSslSocket::encrypted() signal to be emitted, and only after that should my server emit the newConnection() signal. The client code would then think it's using a QTcpSocket, but will in fact be using a secure socket.
But QTcpServer always emits newConnection() after calling incomingConnection() (I looked in the source of QTcpServer):
void QTcpServerPrivate::readNotification()
{
// .........
q->incomingConnection(descriptor);
QPointer<QTcpServer> that = q;
emit q->newConnection();
// .........
}
So my question is, is there a way I can prevent QTcpServer from emitting newConnection(), until I'm ready to emit it myself?
The reason I want this is that I want my class to be able to be used as a drop-in replacement of QTcpServer, by code that is unaware it's using it, so it must behave exactly as a QTcpServer:
QTcpServer* getServer(bool ssl)
{
return ssl ? new SslServer : new QTcpServer;
}
My code for the SslServer class is currently this:
void SslServer::ready()
{
QSslSocket *socket = (QSslSocket *) sender();
addPendingConnection(socket);
emit newConnection();
}
void SslServer::incomingConnection(int socketDescriptor)
{
QSslSocket *serverSocket = new QSslSocket;
if (serverSocket->setSocketDescriptor(socketDescriptor)) {
connect(serverSocket, SIGNAL(encrypted()), this, SLOT(ready()));
serverSocket->startServerEncryption();
} else {
delete serverSocket;
}
}
Here's an idea that could work in this case: redefine the newConnection signal in your QTcpServer subclass.
If you do that, objects that connected with an instance of your server won't receive QTcpServer's "version" of the signal, only the one you emit directly from your sub-class.
Here's a proof of concept: class A is the QTcpServer, foo is the signal you're trying to "hijack", bar is just another (hypothetical) of QTcpServer's signals you don't need to touch.
class A: public QObject
{
Q_OBJECT
public:
A() {};
virtual void doit() {
qDebug() << "A::doit";
emit foo(1);
emit bar(1);
}
signals:
void foo(int);
void bar(int);
};
Class B is your subclass. Notice that it redefines signal foo, but doesn't do anything to bar.
class B: public A
{
Q_OBJECT
public:
B() {};
virtual void doit() {
qDebug() << "B::doit";
emit foo(2);
emit bar(2);
}
signals:
void foo(int);
};
Class C is a potential client, connects the signals/slots from a B instance exactly like it would for an A instance.
class C: public QObject
{
Q_OBJECT
public:
C() {
B *b = new B;
connect(b, SIGNAL(foo(int)), this, SLOT(foo(int)));
connect(b, SIGNAL(bar(int)), this, SLOT(bar(int)));
/* 1 */
b->doit();
/* 2 */
b->A::doit(); // call parent class's function
};
public slots:
void foo(int i) {
qDebug() << "foo: " << i;
}
void bar(int i) {
qDebug() << "bar: " << i;
}
};
Here's the output from constructing a C:
B::doit // this is /* 1 */
foo: 2
bar: 2
A::doit // this is /* 2 */
bar: 1
... and nothing else. A's emit foo(1) isn't connected to C's foo slot, it will never arrive to C. A's emit bar(1) worked as expected, that signal is untouched.
With that setup, you can emit newConnection when your class is ready, QTcpServer's version of the signal will not be received by your user's objects.
To be a true drop in replacement, you probably will need to edit the actual source of Qt, because you normally can't reimplement any Private class calls.
If you are the only one using the replacement one, and you control the classes that connect to the newConnection signal...
Just connect newConnection to your own slot handleNewConnection. When the secure connection is ready emit myNewConnection and connect that to the elements that would have been connected to newConnection.
EDIT:
After a bit of digging, I found an option of to reconnect a signal:
http://qt-project.org/forums/viewthread/6820
Basically, you reimplement QObject::connect, and then you keep track of the connections and process them the way you need to. So in this case, you would keep a list of all the connections of the signal newConnection and keep it in a list so when you disconnect it you could reconnect it. Be sure to call QObject::connect at the end of the reimplementation.
Another option when going this route would be to go and just reroute the connections there. When a connection is requested from newConnection, move it there to myNewConnection.
Hope that helps.
A dirty hack would be to very briefly block the signals from QTcpServer. Since you know that newConnection() will be emitted right after you return from SslServer::incomingConnection(), call this->blockSignals(true); just before you return. That will prevent newConnection() from invoking any slots it is connected to.
To make sure you receive subsequent signals, unblock signals as soon as you can. I suppose the earliest time available would be right when control goes back to the event loop, so a QTimer::singleShot could do it.
void SslServer::incomingConnection(int socketDescriptor)
{
QSslSocket *serverSocket = new QSslSocket;
if (serverSocket->setSocketDescriptor(socketDescriptor)) {
connect(serverSocket, SIGNAL(encrypted()), this, SLOT(ready()));
serverSocket->startServerEncryption();
} else {
delete serverSocket;
}
this -> blockSignals(true);
QTimer::singleShot(0, this, SLOT(unblockSignals());
}
void SslServer::unblockSignals()
{
this->blockSignals(false);
}
The downside of that is that you will lose every signal that could legitimately be emited between incomingConnection() and unblockSignals(). Like I said, it's a dirty hack.