In my Qt5 program I have an interface with some signals.
An implementation of this interface is instanciated at start up and the signals are connected to from different parts of the program (many places).
Now I want to delete that instance and create a new instance, possibly from another implementation, and somehow maintain the signal connections so that all the places that receive the signals does not need to care that the implementation changed.
Is there any way to do this elegantly or do I have to change the architecture of program to keep control over all signal connections in one location (a lot of work)?
Example:
//PS: To be regarded as pseudocode at best, as lots of Qt boilerplate
// and error handling code has been left out, and lots of bugs are left in :-)
struct MyInterface{
virtual void doStuff()=0;
signals:
void someSignal();
}
struct MyImpX:public MyInterface{
void doStuff(){
qDebug()<<"MyImpX";
if((random()%100)<5){
emit someSignal();
}
}
}
struct MyImpY:public MyInterface{
void doStuff(){
qDebug()<<"MyImpY";
if((random()%100)<10){
emit someSignal();
}
}
}
struct MyWorker{
QTimer t;
MyInterface *inst=0;
MyWorker(MyInterface *inst):
inst(inst)
{
connect(&t,SIGNAL(timeout()),this,SLOT(doStuff()));
t.start(100);
}
void setNewInstance(MyInterface *inst){
this->inst=inst;
}
void doStuff(){
if(0!=inst){
inst->doStuff();
}
}
}
struct MyConsumer{
public slots:
void handleIt(){
qDebug()<<"Handling signal";
}
}
void main(){
QApplication app;
MyInterface *inst=new MyImpX();
MyWorker con(inst);
MyConsumer i,j,k,l;
//In this example all the connects are in one place, but
//in reality they are called from several locations that
//Are hard to control.
connect(inst,SIGNAL(someSignal()),&i,SLOT(handleIt()));
connect(inst,SIGNAL(someSignal()),&j,SLOT(handleIt()));
connect(inst,SIGNAL(someSignal()),&k,SLOT(handleIt()));
connect(inst,SIGNAL(someSignal()),&l,SLOT(handleIt()));
//[ ... At this point some time passes where the signal is working ]
//Now the instance changes, so the old connections are lost.
con.setNewInstance(new MyImpY());
delete inst;
inst=0;
//[ ... At this point some time passes where the signal is NOT working ]
app.exec();
}
You could try to implement something based on this question, but I think that'll be hacky at best.
So, instead, you could have a proxy object, which does not get changed, and which can change its connections when the actual object changes. For this, you should probably use signal-signal connections, though you could also write slots which emit signals. Question has pseudocode, so here's some pseudocode as well, to demonstrate the principle.
class MyInterfaceSignalProxy : public MyInterface {
//...
public:
void reconnect(MyInterface *newObj, MyInterface *oldObj=0) {
if(oldObj) disconnect(oldObj, 0, this, 0); // disconnect old connections
connect(newObj, SIGNAL(someSignal()), this, SIGNAL(someSignal()));
}
signals:
void someSignal();
}
Of course you could remove the oldObj parameter, and for example store the currently connected object as private variable, or just not care about disconnection earlier connectios (for example if oldObj will be deleted or otherwise disconnected elsewhere).
And then your main would start something like:
void main(){
QApplication app;
MyInterfaceSignalProxy proxy;
MyConsumer i,j,k,l;
connect(&proxy,SIGNAL(someSignal()),&i,SLOT(handleIt()));
connect(&proxy,SIGNAL(someSignal()),&j,SLOT(handleIt()));
connect(&proxy,SIGNAL(someSignal()),&k,SLOT(handleIt()));
connect(&proxy,SIGNAL(someSignal()),&l,SLOT(handleIt()));
MyInterface *inst=new MyImpX();
proxy.reconnect(inst);
//....
MyInterface *inst2=new MyImpY();
proxy.reconnect(inst2, inst);
delete inst; // whatever
Related
I'm new to the C++ and QT world. I need to do some modifications on an existing console application.
I have the following problem: I'm running some functions (which take some time) concurrently and show a wait indicator during this time. The setup looks like this:
QFuture<void> doStuff = QtConcurrent::run(longCalc, param1, param2);
showWaitIndicator(&doStuff);
// ....
void showWaitIndicator(QFuture<void> *future)
{
while (future->isRunning()) {
// Show some nice indicator and so on.
}
}
This setup works just fine, but now I want to run some other tasks concurrently which have another return type and I need to access the result. Instead of QFuture<void>these are mostly QFuture<double>, QFuture<int>, etc: QFuture<double> doStuff = QtConcurrent::run(doubleCalc);
I also want to display my nice wait indicator, but the different return types mean I can't use my current showWaitIndicator() function.
Is there a good way to improve this "setup"? I'm new to C++, so I'm pretty sure there must be a way. My first idea was function overloading but this didn't work because the parameters have the same type (QFuture).
TL;DR: I need to inform my showWaitIndicator() function that QFuture finished.
You can emit a custom signal from the function that runs concurrently, or use a QFutureWatcher as a source of such signal.
E.g. when longCalc is in the same class:
MyClass::MyClass() {
Q_OBJECT
Q_SIGNAL void longCalcDone();
connect(this, &MyClass::longCalcDone, this, [this]{
...
});
}
void MyClass::longCalc(int arg1, int arg2) {
...
emit MyClass::longCalcDone();
}
E.g. when longCalc is a free function or is in another class:
void longCalc(int, int);
MyClass::MyClass() {
Q_OBJECT
Q_SIGNAL void longCalcDone();
connect(this, &MyClass::longCalcDone, this, [this]{
...
});
void doStuff() {
QtConcurrent::run([=]{
longCalc(param1, param2);
emit longCalcDone();
});
}
}
E.g. with a future watcher instead:
class MyClass : public QObject {
QFutureWatcher watcher;
MyClass() {
connect(&watcher, &QFutureWatcher::finished, this, [this]{
...
});
}
void doStuff() {
auto future = QtConcurrent::run(longCalc, this, param1, param2);
watcher.setFuture(&future);
}
};
The while (future->isRunning()) synchronous code is an anti-pattern. Presumably you invoke QCoreApplication::processEvents within that loop. The problem is - the world is not like that, you can't take the locus of control away from the event loop and pretend that the world revolves around you. Instead, invert the control flow and have your code (a slot, a method or a functor) invoked when the future finishes.
See also this question.
// Example class
class A : public QObject
{
Q_OBJECT
void fun() {
Timer::SingleShot(10, timerSlot); //rough code
}
public slot:
void timerSlot();
}
auto a = SharedPointer<A>(new A);
a->fun();
a->reset(); // a deleted
In this case after a is deleted and timer is fired, would it execute timerSlot()? I'm getting an extremely rare crash and not sure if it's because of something fishy in this logic.
Even if the timer fires, it won't trigger the slot. The docs of ~QObject state: All signals to and from the object are automatically disconnected, and any pending posted events for the object are removed from the event queue. The only way you can trigger the A::timerSlot and delete A at the same time is if you use threads.
You are not obligated to disconnect an object's signals and slots before deleting it.
The QObject destructor will clean up obsolete signal-slot connection for you, as long as you:
Inherit from QObject
Use the Q_OBJECT macro in your class definition
Following these conventions ensures that your object emits a destroyed() signal when deleted. That's actually what Qt's signals-and-slots system uses to clean up dangling references.
You can listen to the destroyed() signal yourself if you'd like to add some debugging code to track object lifecycles.
(Depending on the particular version of Qt/moc you are using, it's quite possible that code with a non-QObject using slots, or a QObject-derived class that doesn't have Q_OBJECT in its header will still compile but cause the timerSlot() method to be invoked on a garbage pointer at runtime.)
I'm getting a extremely rare crash due to timer out of object scope which I need to fire just once. I use QTimer::singleShot which is static method and does not pertain to an instance of QTimer object which I would release with the context it fires the signal to.
That is of course solved in QTimer class and desired behavior controlled by the instance of timer class with non-static QTimer::singleShot property set to true.
// declaration
QScopedPointer<QTimer> m_timer;
protected slots:
void onTimeout();
// usage
m_timer.reset(new QTimer);
m_timer->setSingleShot(true);
QObject::connect(m_timer.data(), SIGNAL(timeout()), this, SLOT(onTimeout()));
m_timer->start(requiredTimeout);
So, no crash should happen due to timer released with the context object.
Edit: This answer was in response to the original question which did not use QObject but had class A as a standalone class inheriting nothing. The question was later edited making this answer obsolete, but I'll leave it here to show what would be needed if not using QObject.
The only way you can do that is if you keep the object alive until the timer has fired. For example:
class A : enable_shared_from_this<A> {
void fun() {
QTimer::singleShot(10, bind(&A::timerSlot, shared_from_this()));
}
public:
void timerSlot();
}
auto a = SharedPointer<A>(new A);
a->fun();
a->reset(); // a goes out of scope, but its referent is kept alive by the `QTimer`.
The reason the above works is that you capture a shared_ptr to class A when setting the timer, and the timer will hold onto it (else it can't fire).
If you don't like or can't use recent C++ features or Boost:
struct Functor {
Functor(SharedPointer<A> a) : _a(a) {}
void operator() { a->timerSlot(); }
SharedPointer _a;
};
class A {
void fun(shared_ptr<A> self) {
QTimer::singleShot(10, Functor(self));
}
public:
void timerSlot();
}
auto a = SharedPointer<A>(new A);
a->fun(a);
To reach certainty, you can stop the timer yourself:
class A : public QObject {
QTimer t;
A() { connect(Signal-Slots); }
~A() { t.stop(); }
fun() { t.start(10); }
...
};
I have simple Qt form which represents main window of my app. It has method:
void gui_popup::on_pushButton_clicked()
{
QString text = ui->MainText->toPlainText();
text = "1\n" + text;
ui->MainText->setText(text);
}
Also I have some code, running in another thread, created like this:
std:thread* core_thread = new thread(&Init); //void Init()...
Then, at some moment or condition code from std::thread need to call gui_popup::on_pushButton_clicked(). I'm trying to do it like this:
void test_callback(void* object_ptr)
{
auto this_object = (gui_popup*)object_ptr;
this_object->on_pushButton_clicked();
}
In std::thread code I'm saving test_callback pointer and gui_popup object pointer. But when it starts calling on_pushButton_clicked() program halts with segmentation fault error. This code works fine with some other simple classes, but not with QtObject. What am I doing wrong?
UPDATE:
I've solved it this way:
void test_callback(void* object_ptr)
{
QMetaObject qtmo;
qtmo.invokeMethod((gui_popup*)object_ptr, "on_pushButton_clicked");
}
it is, of course, much more complex than using QThread, emitting signals and all other suggested solutions. However thank you everyone for trying to help.
I usually solve it like this:
class Foo : public QObject
{
Q_OBJECT
Foo()
{
// connect to own signal to own slot and hence "translate" it
connect(this, SIGNAL(some_signal(QString)),
this, SLOT(some_slot(QString)));
}
signals:
void some_signal(QString s);
protected slots:
void some_slot(QString s)
{
// do something with your gui
}
public:
void callback_proxy(std::string s)
{
emit some_signal(QString::fromUtf8(m_string.c_str()));
}
};
and then the tread does not need to know about QT:
void thread_run_function(Foo* foo)
{
foo->callback_proxy("Hello from Thread!");
}
As far as I understood this is save because the connect (signal,slot) does have a additional default parameter (Qt::ConnectionType type which defaults to Qt::AutoConnection). This tells QT to dispach signals into the qt main event loop if they originate from a foreign thread. Note that using this connection type essentialy makes qt decide on runtime whether to dispatch the signal or call the slot immediately.
HtH Martin
Edits: Some more info on default parameter and this link as reference:
See http://doc.qt.io/qt-5/qt.html#ConnectionType-enum
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.
Boost.Signals allows various strategies of using the return values of slots to form the return value of the signal. E.g. adding them, forming a vector out of them, or returning the last one.
The common wisdom (expressed in the Qt documentation [EDIT: as well as some answers to this question ]) is that no such thing is possible with Qt signals.
However, when I run the moc on the following class definition:
class Object : public QObject {
Q_OBJECT
public:
explicit Object( QObject * parent=0 )
: QObject( parent ) {}
public Q_SLOTS:
void voidSlot();
int intSlot();
Q_SIGNALS:
void voidSignal();
int intSignal();
};
Not only doesn't moc complain about the signal with the non-void return type, it seems to actively implement it in such a way as to allow a return value to pass:
// SIGNAL 1
int Object::intSignal()
{
int _t0;
void *_a[] = { const_cast<void*>(reinterpret_cast<const void*>(&_t0)) };
QMetaObject::activate(this, &staticMetaObject, 1, _a);
return _t0;
}
So: according to the docs, this thing isn't possible. Then what is moc doing here?
Slots can have return values, so can we connect a slot with a return value to a signal with a return value now? May that be possible, after all? If so, is it useful?
EDIT: I'm not asking for workarounds, so please don't provide any.
EDIT: It obviously isn't useful in Qt::QueuedConnection mode (neither is the QPrintPreviewWidget API, though, and still it exists and is useful). But what about Qt::DirectConnection and Qt::BlockingQueuedConnection (or Qt::AutoConnection, when it resolves to Qt::DirectConnection).
OK. So, I did a little more investigating. Seems this is possible. I was able to emit a signal, and receive value from the slot the signal was connected to. But, the problem was that it only returned the last return value from the multiple connected slots:
Here's a simple class definition (main.cpp):
#include <QObject>
#include <QDebug>
class TestClass : public QObject
{
Q_OBJECT
public:
TestClass();
Q_SIGNALS:
QString testSignal();
public Q_SLOTS:
QString testSlot1() {
return QLatin1String("testSlot1");
}
QString testSlot2() {
return QLatin1String("testSlot2");
}
};
TestClass::TestClass() {
connect(this, SIGNAL(testSignal()), this, SLOT(testSlot1()));
connect(this, SIGNAL(testSignal()), this, SLOT(testSlot2()));
QString a = emit testSignal();
qDebug() << a;
}
int main() {
TestClass a;
}
#include "main.moc"
When main runs, it constructs one of the test classes. The constructor wires up two slots to the testSignal signal, and then emits the signal. It captures the return value from the slot(s) invoked.
Unfortunately, you only get the last return value. If you evaluate the code above, you'll get: "testSlot2", the last return value from the connected slots of the signal.
Here's why. Qt Signals are a syntax sugared interface to the signaling pattern. Slots are the recipients of a signal. In a direct connected signal-slot relationship, you could think of it similar to (pseudo-code):
foreach slot in connectedSlotsForSignal(signal):
value = invoke slot with parameters from signal
return value
Obviously the moc does a little more to help in this process (rudimentary type checking, etc), but this helps paint the picture.
No, they can't.
Boost::signals are quite different from those in Qt. The former provide an advanced callback mechanism, whereas the latter implement the signaling idiom. In the context of multithreading, Qt's (cross-threaded) signals depend on message queues, so they are called asynchronously at some (unknown to the emitter's thread) point in time.
Qt's qt_metacall function returns an integer status code. Because of this, I believe this makes an actual return value impossible (unless you fudge around with the meta object system and moc files after precompilation).
You do, however, have normal function parameters at your disposal. It should be possible to modify your code in such a way to use "out" parameters that act as your "return".
void ClassObj::method(return_type * return_)
{
...
if(return_) *return_ = ...;
}
// somewhere else in the code...
return_type ret;
emit this->method(&ret);
You may get a return value from Qt signal with the following code:
My example shows how to use a Qt signal to read the text of a QLineEdit.
I'm just extending what #jordan has proposed:
It should be possible to modify your code in such a way to use "out" parameters that act as your "return".
#include <QtCore>
#include <QtGui>
class SignalsRet : public QObject
{
Q_OBJECT
public:
SignalsRet()
{
connect(this, SIGNAL(Get(QString*)), SLOT(GetCurrentThread(QString*)), Qt::DirectConnection);
connect(this, SIGNAL(GetFromAnotherThread(QString*)), SLOT(ReadObject(QString*)), Qt::BlockingQueuedConnection);
edit.setText("This is a test");
}
public slots:
QString call()
{
QString text;
emit Get(&text);
return text;
}
signals:
void Get(QString *value);
void GetFromAnotherThread(QString *value);
private slots:
void GetCurrentThread(QString *value)
{
QThread *thread = QThread::currentThread();
QThread *mainthread = this->thread();
if(thread == mainthread) //Signal called from the same thread that SignalsRet class was living
ReadObject(value);
else //Signal called from another thread
emit GetFromAnotherThread(value);
}
void ReadObject(QString *value)
{
QString text = edit.text();
*value = text;
}
private:
QLineEdit edit;
};
To use this, just request call();.
You can try to workaround this with following:
All your connected slots must save their results in some place (container) accessible from signaling object
The last connected slot should somehow (select max or last value) process collected values and expose the only one
The emitting object can try to access this result
Just as an idea.