Qt and C++ how to share items from classes - c++

My problem is: I'm using an example made by Qt as educational (it's a terminal to send and receive serial data). I need to create a QTimer starting in a function built in a class and stop it in another function built in a different class.
Qtimer obviously works with no problem in function declared in the same class where Timer is; but it remains unknown in the class built to the other class.
How can I solve?

You may want to use the Qt SIGNAL / SLOT system. Then you may have something like that:
class A : public QObject
{
Q_OBJECT
//...
public slots:
stopTimerHandler() {timer.stop();}
private:
QTimer timer;
};
class B : public QObject
{
Q_OBJECT
//...
private:
stopTimer() {emit stopTimerSig();}
signals:
stopTimerSig();
};
// somewhere
A a;
B b;
connect(&b, SIGNAL(stopTimerSig()), &a, SLOT(stopTimerHandler())); // old connect version
// or ( ty #eyllanesc for the new syntax )
QObject::connect(&b, &B::stopTimerSig, &a, &A::stopTimerHandler); // qt5
B emit a signal listened by A, when A receive the signal, A stops his timer.

Related

Alternatives to Qt Signals and Slots for Inter-Object Communication

What are alternatives to using Qt-like signals and slots for communication between two objects (class instances) in both directions?
I know this can be realized by saving a reference of the other in each object. However, this gets sort of confusing when there are many different objects and all objects are supposed to interact with (and thus to know) one another.
The other question I've had was how Qt signals and slots implement this inter-object communication internally (a simple overview of the internal course of events would be helpful)?
A Qt example of what I'm talking about would be the following. Both objects, c and d, can emit a signal that is connected to a slot of the other.
class Chicken : public QObject
{
Q_OBJECT
public:
Chicken() = default;
public slots:
void helloBackDuck() {
std::cout << "Hello Back Duck" << std::endl;
}
signals:
void helloDuck();
};
class Duck : public QObject
{
Q_OBJECT
public:
Duck() = default;
public slots:
void helloBackChicken() {
std::cout << "Hello Back Chicken" << std::endl;
}
signals:
void helloChicken();
};
int main() {
Chicken c;
Duck d;
connect(&c, &Chicken::helloDuck, &d, &Duck::helloBackChicken);
connect(&d, &Duck::helloChicken, &c, &Chicken::helloBackDuck);
}
Qt Signal and slot mechanism is best choose in Qt programs, but if you want to know about other options, you have these:
You can develop your own Observer structure that would be like Qt signal and slot but you should invent the wheel from the beginning by yourself.
You should create an Observe class and a Subject class. In the beginning connect your Observer by passing a reference of it to Subject and as soon as the condition meet Subject will call the update function of all of the instances (emit).
For more explanation check this link.
Another option is using Boost signal2 that is also similar to Qt signal slot but from third party libraries. Usage is similar to Qt signal.
For more explanation check this.

QT connect signal and slot in from different classes to mainwindow class?

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.

Exposing internal component of a class in order to prevent writing too much code and impact on performance

Let's say I have a class
class B : public class QObject {
Q_OBJECT
public:
B(QObject* parent=Q_NULLPTR);
signals:
void signalData(int data);
public slots:
void slotGetData();
private:
}
The slotGetData() is triggered externally and basically retrieves some data from somewhere and sends it back using signalData(int data). On the other hand I also have another class
class A : public class QObject {
Q_OBJECT
public:
A(QObject* parent=Q_NULLPTR) {
// Init B, move to thread, setup timer, connect timer's timeout to B's slotGetData()
// Connect B to A
connect(this->B, SIGNAL(signalData(int)), this, SLOT(slotGetData(int)));
}
signals:
// Emit signal containing data to another Qt component
void signalData(int x);
private slots:
// Connect B::signalData(int x) to this slot and re-emit the data using A::signalData(int x). Don't do anything with the data!
void slotGetData(int x);
private:
B* workerObj;
QThread worker;
QTimer workerTimer;
}
which basically is responsible for instantiating workerObj, moving it to worker thread and connecting the workerTimer's timeout() signal to B::slotGetData().
The purpose of this class is to enable proper integration (multi-threaded) of B inside a third-party class that wants to use it for example:
class ThirdParty : public class QWidget {
Q_OBJECT
public:
ThirdParty(QObject* parent=Q_NULLPTR) {
// Init A
// Connect to B through A
connect(this->integrationObj, SIGNAL(signalData(int)), this, SLOT(slotGetData(int)));
}
private slots:
// Connect A::signalData(int x) to this slot and do something with the x (change UI, whatever)
void slotGetData(int x);
private:
A* integrationObj;
}
The class ThirdParty gains indirect access to specific features of B through A.
Now the dilemma I'm facing is the following:
Should I just relay the data signal which comes from B through A and expose it as a signal of A or
Should I just return a const reference to B to allow an class which has A in it (so that it can use B) to directly connect to B's signalData(int x)?
In the first case (which I have) I basically have to mirror every single signal B wants to offer to the outside inside A (by providing the respective private slots in A and also signals that are basically the same as B's). Needless to say this leads to having too much of the same stuff and also has some (even if just slight) performance impact since I get 2 signal emissions (from B to A and then from A to whichever other object has A) and 2 slot calls (one in A to get signal from B and one in whichever other object has A to get signal from A).
The second case seems nice but I fear that I will expose features of B which the class containing A may not be allowed to have access to
If the second case is implemented I would have something like this (B doesn't change):
class A : public class QObject {
Q_OBJECT
public:
A(QObject* parent=Q_NULLPTR);
const B* getB() const; // Return a reference to B that cannot be changed but can be used to expose B's slots and signals
signals:
private slots:
private:
B* workerObj;
QThread worker;
QTimer workerTimer;
}
class ThirdParty : public class QWidget {
Q_OBJECT
public:
ThirdParty(QObject* parent=Q_NULLPTR) {
// Init A
// Connect to B directly!
connect(this->A->getB(), SIGNAL(signalData(int)), this, SLOT(slotGetData(int)));
}
private slots:
// Connect B::signalData(int x) to this slot and do something with the x (change UI, whatever)
void slotGetData(int x);
private:
A* integrationObj;
}
What should I do here? Sadly there are no private signals hence all B signals but also all of its public slots will be exposed. If all these are to be used, there is no issue with this degree of exposure but otherwise...not so much.
facepalm I already had the solution in another project of mine. :D I just need to provide a connectTo(QObject* thirdparty) inside A, which internally connects the thirdparty slot only to specific signal of B thus not exposing things from B that are not meant to be exposed!
Another better solution is to use a signal-to-signal connection (connect(const QObject *sender, const char *signal, const char *method, Qt::ConnectionType type)) or use the child-parent relation though in the latter I have to make sure that the parent actually is set. This is also known as signal forwarding and requires 2 signals but no extra slots. Since A is visible to ThirdParty I can do (this here represents ThirdParty) connect(this, SIGNAL(signalFromThirdPartyToB()), this->a, SIGNAL(signalFromAToB())) to set the forwarding of ThirdParty signals to B through A and then do the actual signal-slot connection between the forwarding signal in A to a slot in B by calling (this here represents A) connect(this, SIGNAL(signalFromAToB()), this->b, SLOT(slotB())).

SIGNALS and SLOTS in QT5

I've encountered a following issue:
I have a GUI element class and a Thread class. I would like to exchange signals between them. However it only works in one direction. I can successfuly send a signal from main GUI window to the thread. However when I want to send a signal from the thread to the process that calls the thread, but it doesn't work. Here is how I do it:
bool GfxMapItem::mapSwitch(int seqidx)
{
...
importMapThread_ = new ImportMapThread(sequence_->item(seqidx));
connect(GUI_UI->analExportButton, SIGNAL(clicked()), importMapThread_, SLOT(interrupt1()), Qt::QueuedConnection); //<-- this one works perfectly
connect(importMapThread_, SIGNAL(progress(int)), this, SLOT(loadMap(int)), , Qt::QueuedConnection); // <-- this one unfortunatelly doesn't
...
}
The thread code is very simple and it only emits the signal (I've check that it works when I connect the thread with itself).
void ImportMapThread::run()
{
QLOGX("Running ImportMapThread...");
QLOGINC;
emit this->progress(100);
QLOGX("Stopping ImportMapThread...");
}
The thread header looks like the one below:
class ImportMapThread : public InterruptibleThread
{
Q_OBJECT
private:
...
protected:
...
public:
ImportMapThread(SeqItem *p);
signals:
void progress(int value);
void progressReset(int value);
public slots:
virtual void interrupt1();
void loadMap();
protected:
virtual void run();
};
And the class that calls that thread looks like this:
class GfxMapItem : public QObject, public QGraphicsPixmapItem
{
Q_OBJECT
...
signals:
void mouseOutside();
void mouseMove(const QPointF &pos);
private slots:
void loadMap(int);
protected:
...
};
Any ideas? Please, I've ran out of ideas.
I believe, you should call exec in your run-implementation. Exec starts event-loop which should allow to send signals.
Take a look at:
int QThread::exec() [protected] Enters the event loop and waits until
exit() is called, returning the value that was passed to exit(). The
value returned is 0 if exit() is called via quit(). It is necessary to
call this function to start event handling.
I hope this helps.
Solved! It turned out that only the GUI elements can communicate with the threads. The thread can be inherited from other type of the thread and there isn't any problem neither with the signals nor the slots. The problem was laying in the object GfxMapItem. For some reason it just couldn't handle normal communication.

Qt4: connect slot and signal from other forms

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.