I want to implement signal and slot between two classes mainwindow and reader.
Inside the reader class I declare the signal SetProgress:
reader.h
class reader :public QObject
{
Q_OBJECT
signals:
void SetProgress(QString sOperation, int nPercentage);
}
reader.cpp
void reader::UpdateProgress(double amount)
{
int nPrecentage = (100 * amount / (max- min));
emit SetProgress(m_sCurrentOperation, nPrecentage);
}
mainwindow.h
public:
reader *MyReader
private slots:
void SlotDisplayProgress(QString sActivity_i, int ProgressPercentage_i);
mainwindow.cpp
void mainwindow :: SlotDisplayProgress(QString sActivity_i, int nProgressPercentage_i)
{
this->ui->QprogressBar->setValue(nProgressPercentage_i);
}
inside Mainwidow.cpp I will declare signal and slot
MyReader = reader::New();
connect ( MyReader, &reader::SetProgress, this, &mainwindow::SlotDisplayProgress );
I tried debugging and everything works correctly till the emit part. However, the slot is never executed.
Try setting Qt::DirectConnection:
connect ( MyReader, &reader::SetProgress, this, &mainwindow::SlotDisplayProgress, ***Qt::DirectConnection***);
I had a problem like this, where I connected the signal and slot, and it only worked when I defined the type of connection.
I hope this helps.
PS. I don't know if this depends on the version of QT but when I connect signals and slots the syntax I write is the following:
ImageURLLoadListener* downloader = new ImageURLLoadListener(&id, socket);
connect(downloader, SIGNAL(imageLoaded(QString*,QTcpSocket*)), this, SLOT(on_resourceImageDownload(QString*,QTcpSocket*)), Qt::DirectConnection);
I don't know if it's related or not...
Is MyReader pointer? Use &MyReader if not so.
Related
I am trying to perform interthread communication in Qt (C++). I have a worker thread which does some calculations and I want the workerthread to return its results to the main thread when done. I therefor use a connect, I know thanks to debugging, that the signal is successfully being emit but that it is the slot that isn t being executed and I don t understand why.
The relevant pieces of code:
webcamClass::webcamClass(QObject *parent) : QObject(parent)
{
workerThread = new QThread(this);
workerClassObj = new workerClass();
//connect for image
connect(workerClassObj, SIGNAL(mySignal(QPixmap)), this, SLOT(mySlot(QPixmap)));
//connect(&workerClassObj, workerClass::mySignal(QPixmap), this, webcamClass::mySlot(QPixmap));
connect( workerThread, SIGNAL(started()), workerClassObj, SLOT(getImage()) );
workerClassObj->moveToThread(workerThread);
}
void webcamClass:: foo()
{
workerThread->start();
}
void workerClass::getImage()
{
qint64 successFailWrite;
QImage img;
QPixmap pixmap;
... do some stuff with pixmap...
qDebug()<<"going to emit result";
emit mySignal(pixmap);
qDebug()<<"emitted";
}
void webcamClass::mySlot(QPixmap p)
{qDebug()<<"this message should be displayed"; }
The corresponding header files:
class workerClass : public QObject
{
Q_OBJECT
private:
public:
explicit workerClass(QObject *parent = nullptr);
signals:
void mySignal(QPixmap);
};
webcamClass::webcamClass(QObject *parent) : QObject(parent)
{
Q_OBJECT
public:
explicit webcamClass(QObject *parent = nullptr);
public slots:
void mySlot(QPixmap p);
private:
QThread *workerThread;
workerClass *workerClassObj;
};
The code above just outputs:
going to emit result
emitted
but unfortunately doesn t output this message should be displayed.
webcamClass belongs to the parent thread, while workerClass belngs to -you guessed it- the worker thread.
Could someone explain how to setup my connect so that mySlot() gets triggered?
Thanks!
In the code you pasted in pastebin.com/UpPfrNEt you have a getVideoFrame method that uses while (1). If this method is called, it runs all the time and blocks the event loop from handling signals. You can solve it in many ways, I think the best practice will be to replace the while(1) with something else.
If possible, I highly encourage you to use the new Signal Slot syntax:
connect( SOURCEINSTANCE, &CLASS::SIGNAL, TARGETINSTANCE, &CLASS::SLOT );
In your case, that could be:
connect( workerClassObj, &workerClass::mySignal, this, &webcamClass::mySlot );
Specificallyfor your case, if you want to pass Signals and Slots between threads, you have to be careful. First, check the connection type for the connect call, its acutally the last parameter.
connect( workerClassObj, &workerClass::mySignal, this, &webcamClass::mySlot, Qt::QueuedConnection );
For a detailed explanation look here:
http://doc.qt.io/qt-5/signalsandslots.html
If you want to pass custom types, you have to declare them as metatypes first.
Add e.G. this in your constructor:
qRegisterMetaType("MyDataType");
Please make sure, that your custom datatype has a default constructor and be aware that afaik, references cannot be passed across threads.
I have a problem creating a QPushButton and linking its signal to my slots. First, I created a class with the slot:
class A : public QWidget{
public slots:
void handleButton();
};
There is my handleButton function in the .cpp
void A::handleButton(int row, int col){
m_button->setText("Example");
// resize button
m_button->resize(100,100);
}
Then I want to connect the button.
QObject::connect(m_button, SIGNAL(clicked()), qApp, SLOT(handleButton()));
But I got an error when I start the application:
"No such slot"
Make sure that qApp is an object of class A (i.e. where your slot is defined).
That said, the signatures are wrong: a signal links to a slot only if the signature match
http://qt-project.org/doc/qt-4.8/signalsandslots.html
The signals and slots mechanism is type safe: The signature of a signal must match the signature of the receiving slot.
And your slot hasn't the right signature:
http://qt-project.org/doc/qt-4.8/qabstractbutton.html#clicked
void QAbstractButton::clicked ( bool checked = false ) [signal]
You have a few errors in this code, if you define "void handlebutton()" then you must implement void handlebutton() NOT void handlebutton(inx x, int y) this code should not even compile.
More: in QT you CAN ONLY connect SIGNALS and SLOTS with the same parameters so you can connect SIGNAL(clicked()) with SLOT(handlebutton()) but not SIGNAL(clicked() with SLOT(handleButton(int, int)).
Another problem is that connect is executed at runtime so You must compile and run before Qt can show you the error.
So a possible solution is:
define and implement the slot void handlebutton() and connect that to the signal clicked(), then define another method handleButton (int x, int y) that you will call from inside handleButton().
I really hope that makes sense to you.
Your class definition should look like :
class A : public QWidget
{
Q_OBJECT
public slots:
void handleButton(int, int);
};
And you should connect it like:
QObject::connect(m_button, SIGNAL(clicked()),qApp, SLOT(handleButton(int a, int b)));
where a and b are variables for row and column.
This should work. Try understanding basic C++. :)
I have a small problem. I want run function in MainWindow from AnotherWindow. I can't set connect() for it.
Main class: MainWindow
Other form: AnotherWindow
Function in main class: setVariable(QString)
Function in other form: btnClicked()
I have now connected button signal clicked():
// In AnotherWindow.cpp
connect(ui->btnOK, SIGNAL(clicked()), this, SLOT(btnOkClicked()));
// Function in same file
void interfaceWindow::btnOkClicked() {
/* Some actions - emit signal? */
this->close();
}
btnOkClicked() are declared as private slot.
// In MainWindow.cpp
void MainWindow::setVariable(QString _var) {
this->var = _var;
}
setVariable(QString) are declared as public slot.
How I can send variable from AnotherForm (from btnOkClicked() function) to MainWindow (setVariable(QString) function) ? How and where I must send signal and make connection?
I readed about signals and slots, but my code don't work - I don't paste it here because it's terrible :)
Any help for Qt newbie?
You need to have an reference of AnotherWindow in MainWindow OR vice versa. Then you need the following things:
// AnotherWindow.h
signals:
void buttonOkClickedSignal(QString var);
// AnotherWindow.cpp
void interfaceWindow::btnOkClicked() {
emit buttonOkClickedSignal("The button got clicked!");
this->close();
}
Next step varies based on whether MainWindow has reference to AnotherWindow or vice versa. You can either:
// AnotherWindow.cpp
connect(this, SIGNAL(buttonOkClickedSignal(QString), &mainWindow, SLOT(setVariable(QString)));
or:
// MainWindow.cpp
connect(&anotherWindow, SIGNAL(buttonOkClickedSignal(QString), this, (SLOT(setVariable(QString)));
If you are invoking the slot through signal it shouldn't matter whether it's private or public (see Qt Documentation).
Hope this helps.
I'm not entirely sure I understand your question, but let me try.
You want to be able to fire a slot in another class. There are a few ways you can do that.
Declare one as a friend class to the other. Then they can see the protected and private variables/memebers
It is possible to make slots static so you can call them without a class object.
For example,
class MainWindow {
private slot:
void setVariable(QString);
}
class AnotherWindow {
friend class MainWindow;
MainWindow *window;
public:
AnotherWindow() {
connect(this, SIGNAL(fire(QString)), window, SLOT(setVariable(QString)));
}
signals:
void fire(QString);
public slots:
void onButtonClicked() {
emit fire(QString);
}
}
The previous is pseudocode so don't expect it to compile. I think this is what you want. Basically since your slot is private on MainWindow you need to make it a friend. To connect, it needs to be a member. Then when the onButtonClicked slot is evoked, then it fire()s the setVarialbe() slot.
Here is a simple code for your another window:
class MyWidget : public QWidget
{
Q_OBJECT
public:
MyWidget(QWidget * parent = 0)
{
okBtn = new QPushButton ("I am Ok!");
MyData = "";
connect(okBtn ,SIGNAL(clicked()),this,SLOT(OnOk()));
}
~MyWidget();
private:
QString MyData;
QPushButton * okBtn;
//something that modify string MyData
signals:
void MyDataSignal(QString);
//Internal slot that emits signal with proper data
private slots:
void OnOk()
{
if(MyData!="")
{
emit MyDataSignal(MyData);
}
}
};
Now in MainWindow create an object of MyWidget (suppose myWid)and connect it to slot
connect(myWid, SIGNAL(MyDataSignal(QString)),this,SLOT(OnMyWidOkClicked(QString)));
the signal will pass string to slot.
While making signals and slots keep in mind following points:
To connect a signal to a slot (or to another signal), they must have the same parameter
Parameters should be in the same order in both signal and slot.
if a signal has more parameters than the slot it is connected to, the additional parameters are simply ignored but opposite is not possible.
If you will connect a signal that have unmatched parameters to slot then no compile time error will occur but at run time command window will show a warning that signal/slot/connection does not exist.
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()).
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.