Accessing the QPushButton in the callback function - c++

I want to enable a pushbutton in a callback function. I have tried to do the following but I have got:
Runtime received SIGSEGV (address: 0x28 reason: address not mapped to object)
class MyWindow: public QDialog
{
Q_OBJECT
public:
QPushButton *Btn;
void Scan();
....
};
extern void StartScan(pfcallback);
void MyWindow::Scan()
{
Btn->setEnabled(false);
StartScan(Scanfinished);
}
void static Scanfinished()
{
Btn->setEnabled(true);
}
How to access the button in the callback function Scanfinished() ?

You're attempting to manually manage memory. As you can see, it's very easy to use a dangling pointer or commit other blunders. Instead, let the compiler do it for you.
You use static incorrectly.
If I were to do it, I'd do as follows. The destructor is generated by the compiler and will correctly release all resources and reset m_instance to a null value.
class MyWindow : public QDialog
{
Q_OBJECT
static QPointer<MyWindow> m_instance;
QVBoxLayout m_layout{this};
QPushButton m_button{"Scan"};
public:
MyWindow(QWidget * parent = nullptr) : QDialog(parent) {
Q_ASSERT(! m_instance);
m_instance = this;
m_layout.addWidget(&m_button);
}
void Scan();
static void ScanFinished();
};
QPointer<MyWindow> MyWindow::m_instance;
void StartScan(void(*callback)());
void MyWindow::Scan()
{
m_button.setEnabled(false);
StartScan(ScanFinished);
}
void MyWindow::ScanFinished()
{
m_instance->m_button.setEnabled(true);
}
At this point it's rather obvious that the API of StartScan is horribly broken, and this brokenness forces the use of a singleton MyWindow. When doing any kind of callbacks, you never use a sole C function pointer. You must accept both a function pointer that takes a void* and a void* that will be used to carry the data the function needs to work. This is an idiom. If you use C-style callbacks, you cannot not use the idiom without severely crippling the usability of your API.
Thus, this is a complete example and works in both Qt 4 and Qt 5. You should have posted something like it - a self-contained test case - in your question. It compiles and it works and you can even get the complete Qt Creator project from github. It will compile and run on all platforms supported by current Qt. It's not supposed to be hard: that's why you're using Qt, after all. Getting in the habit of creating such concise test cases to demonstrate your issues will make you a better developer, and make your questions much easier to answer.
// https://github.com/KubaO/stackoverflown/tree/master/questions/simple-callback-43094825
#include <QtGui>
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
#include <QtWidgets>
#include <QtConcurrent>
#endif
class MyWindow: public QDialog
{
Q_OBJECT
QVBoxLayout m_layout{this};
QPushButton m_button{"Scan"};
Q_SIGNAL void ScanFinished();
public:
MyWindow(QWidget * parent = nullptr) : QDialog(parent) {
m_layout.addWidget(&m_button);
connect(&m_button, SIGNAL(clicked(bool)), this, SLOT(Scan()));
connect(this, SIGNAL(ScanFinished()), this, SLOT(OnScanFinished()));
}
Q_SLOT void Scan();
static void ScanFinishedCallback(void* w);
Q_SLOT void OnScanFinished();
};
void StartScan(void(*callback)(void*), void* data) {
// Mockup of the scanning process: invoke the callback after a delay from
// a worker thread.
QtConcurrent::run([=]{
struct Helper : QThread { using QThread::sleep; };
Helper::sleep(2);
callback(data);
});
}
void MyWindow::Scan()
{
m_button.setEnabled(false);
StartScan(ScanFinishedCallback, static_cast<void*>(this));
}
void MyWindow::ScanFinishedCallback(void* data)
{
emit static_cast<MyWindow*>(data)->ScanFinished();
}
void MyWindow::OnScanFinished()
{
m_button.setEnabled(true);
}
int main(int argc, char ** argv) {
QApplication app(argc, argv);
MyWindow w;
w.show();
return app.exec();
}
#include "main.moc"
Of course StartScan cannot do the work in the thread it was called from: it'd block the GUI thread and make your application unresponsive. That's the prime source of bad user experience. Instead, it should spawn a concurrent job that will notify the caller when the scanning is done.
Since the callback will be called from that concurrent thread, it's not safe to use MyWindow's non-thread-safe methods. The only thread-safe methods are signals - thus we can emit a signal that Qt will the safely forward to MyWindow's thread and invoke OnScanFinished from the right thread.

Related

How to emit a Qt signal from inside a function pointer?

While implementing the interface to a device there is code like the following in MyClass constructor
pDeviceInstance = new Device()
pDeviceInstance->loadLibrary();
pDeviceInstance->Create(functionpointer)
There are asyncronous events comming out and calling functionpointer (which I would like to deal with).
Both functionpointer and pDeviceInstance are static.
I would like to emit a Qt signal from inside functionpointer but because it is static its not possible to emit the signal.
I tried:
To make functionpointer a lambda in the hope to emit signals from inside the lambda.
But for that to happen lambda needs to capture this,
and in order for the lambda to decay to a function pointer it cannot capture anything.
To make functionpointer non static but in that case it seems to be a function pointer of MyClass
which is different type.
So, I'm running out of options in my plan of emit a Qt signal from inside that functionpointer.
Is there anything I'm missing here?
Not a problem at all. Hook up a QObject with the signals you desire as a child of qApp (QApplication::instance), and then use it via the global qApp pointer:
class MySignaler : public QObject {
Q_OBJECT
public:
MySignaler(QObject *parent = nullptr) : QObject(parent) {
setParent(qApp);
}
Q_SIGNAL void deviceActivity();
static bool emitDeviceActivity() {
if (!qApp) return false;
auto *self = qApp->findChild<MySignaler*>();
if (!self) return false;
emit self->deviceActivity();
return true;
};
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
MySignaler signaler;
Device device;
device.loadLibrary();
device.create(&MySignaler::emitDeviceActivity);
// ...
}

Is it safe to delete a heap allocated object inside a slot across different threads?

I am trying to analyse a segfault that seems to occur when accessing a heap allocated object created by a sender thread and accessed by a receiver thread.
Here is a short version of the code :
#include <QCoreApplication>
#include <QDebug>
#include <QThread>
#include <QTimer>
class Data
{
public:
Data(int data1) : m_data1(data1) {}
int data1() {
return m_data1;
}
private:
int m_data1;
};
class Sender : public QObject
{
Q_OBJECT
public:
Sender(int timeout) : m_timeout(timeout) {}
public slots:
void startSendingDatas() {
QTimer::singleShot(m_timeout, [this]() {
emit datas(new Data(3));
});
}
signals:
void datas(Data *data);
private:
int m_timeout;
};
class Receiver : public QObject
{
Q_OBJECT
public slots:
void onDatas(Data *data) {
qDebug() << "data1 = " << data->data1();
delete data; // is it always safe ?
}
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Sender sender(5000);
Receiver receiver;
QObject::connect(&sender, SIGNAL(datas(Data*)),
&receiver, SLOT(onDatas(Data*)));
QThread worker;
worker.start();
sender.moveToThread(&worker);
// now we call it asynchronously
QMetaObject::invokeMethod(&sender, "startSendingDatas");
return a.exec();
}
#include "main.moc"
Data does not inherits from QObject so deleteLater is not an option here but is it really safe to do that ?
Thank you.
Yes it is 'safe' to do so if you can garantee that the pointer will still be valid when you`ll access it.
In this simple example that seems the case. I see a potential issue in your code that might be the cause of your random crash :
Event driven objects may only be used in a single thread. Specifically, this applies to the timer mechanism and the network module. For example, you cannot start a timer or connect a socket in a thread that is not the object's thread.
from https://doc.qt.io/qt-5/threads-qobject.html paragraph Object reentrancy.
This is what you are doing : sender object is created on the main thread and on so the timer is started on this thread, then it is moved to the worker thread.
Another thing that I am not 100% confident about : you perform the connection before moving the object to the other thread. By default if nothing is said about the connection, when two objects are on the same thread, it is a direct connection, and when object are on different thread, it´s obviously a queued connection. I don´t know to which extend Qt is robust to changing the connection type when an object is moved, but I would rather first move the object and then connect it.

RAII and Qt signals

I'm trying to understand and use RAII and wanted opinions on this implementation:
I want the RAII PauseProcessRAII to emit a signal and another one in the destructor. Example:
// Header
public:
PauseProcessRAII(QObject *parent = 0);
void Execute();
~PauseProcessRAII();
signals:
void PauseProcess(bool pause_process);
// Source
PauseProcessRAII::~PauseProcessRAII()
{
emit PauseProcess(false);
}
void PauseProcessRAII::Execute()
{
emit PauseProcess(true);
}
// MainWindow code
void MainWindow::OnPauseProcessRAII(bool pause_process)
{
qDebug() << "pause_process: " << pause_process;
}
void MainWindow::OnButtonSaveClicked()
{
PauseProcessRAII pauseProcessRAII(this);
connect(&pauseProcessRAII, &PauseProcessRAII::PauseProcess, this, &MainWindow::OnPauseProcess);
pauseProcessRAII.Execute();
// ... Some code runs
// ... pauseRAII desctructor is called
}
When I run the code both emits are firing as expected. My question is this a good solution? At first I though the emit call in PauseProcessRAII destructor wouldn't have worked because it may have destroyed the signal and slot connection. Of course that would mean I would have to add the connect to every function that I use it on.
The whole idea is fundamentally broken if your premise is that the code indicated by "Some code runs" runs long enough to block the GUI. If so: don't do that. The only code that is supposed to ever execute in the GUI thread is short, run-to-completion code that doesn't take long enough for the user to notice.
If the time taken by "Some code runs" is very short - on the order of single milliseconds at most - then you can certainly use such a construct. The term RAII doesn't apply here, as you're dealing with some sort of a scope guard.
If you wish, you can forgo the execute method and perform the connection in the constructor:
// https://github.com/KubaO/stackoverflown/tree/master/questions/scopeguard-signal-34910879
// main.cpp
#include <QtCore>
class ScopeSignaller : public QObject {
Q_OBJECT
public:
Q_SIGNAL void inScope(bool);
template <typename F>
ScopeSignaller(QObject * target, F && slot, QObject * parent = 0) : QObject(parent) {
connect(this, &ScopeSignaller::inScope, target, std::forward<F>(slot));
inScope(true);
}
~ScopeSignaller() {
inScope(false);
}
};
int main(int argc, char ** argv) {
QCoreApplication app{argc, argv};
ScopeSignaller s(&app, +[](bool b){ qDebug() << "signalled" << b; });
}
#include "main.moc"

Signal/Slot with return value doesn't work

I made a signal slot in Qt and the program runs without error or warnings about the connect i made. The problem is that when i want to use the signal slot, it always returns NULL.
Main.cpp
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Game* game = new Game;
Scrabble mainWindow;
mainWindow.show();
QObject::connect(&mainWindow,SIGNAL(getTurn()),game,SLOT(giveTurn()));
return a.exec();
}
Game.h
class Game: public QObject
{
Q_OBJECT
public:
Game(QObject *parent = 0);
~Game();
private:
int m_turn;
public slots:
int giveTurn();
};
Game.cpp
Game::Game(QObject *parent)
:QObject(parent)
{
m_turn = 1;
}
Game::~Game()
{
}
int Game::giveTurn()
{
return m_turn;
}
Scrabble.h
class Scrabble : public QMainWindow
{
Q_OBJECT
public:
explicit Scrabble(QWidget *parent = 0);
~Scrabble();
private:
Ui::Scrabble *ui;
signals:
int getTurn();
};
when i use int turn = emit getTurn(); in Scrabble.cpp, turn will become 0 and not 1.
Does anyone know what i'm doing wrong?
You're using signals and slots incorrectly. Signals cannot return value. See the Signals & Slots documentation page:
Signals are automatically generated by the moc and must not be implemented in the .cpp file. They can never have return types (i.e. use void).
Returning values from signals is not required when you use Qt features correctly. Maybe you should create another question and describe what you want to do and why you need such connection. You're definitely doing something wrong.
Signals/slots cant return any value. Possible solution:
Scrabble:
signal: void requestTurn();
public slot: receiveTurn(int);
Game:
public slot: onrequestTurn();
signal: sendTurn(int);
emit "keyword" is highly undocumented right now, but from Qt's source, it is only empty define, so your code
int turn = emit getTurn();
will be expanded to:
int turn = getTurn();
However, this is not covered in oficial documentation and it might change any time - so - don't use it!
Now, please note that turn variable is not getting value from slot, but from signal. There is nothing about passing return value from slot to signal - and it doesn't make sense (well, it may make sense in your sample, but what if I connect multiply slots to a single signal - what slot will return value, what if slots are executed asynchronously - should we wait for return value, etc.).
You can use regular function call (just call giveTurn() function: int turn = giveTurn()).

Can Qt signals return a value?

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.