Unable to connect to signal from outside class in Qt - qt

I have a EmitSignal class like this:
class EmitSignal : public QObject
{
Q_OBJECT
public:
EmitSignal() {
emit emittedSignal();
qDebug() << "Signal emitted";
}
signals:
void emittedSignal();
};
And in ConnectSlot class, it's like this:
class ConnectSlot : public QMainWindow
{
Q_OBJECT
public:
ConnectSlot() {
connect(&emitSignalObject, &EmitSignal::emittedSignal, this, &ConnectSlot::connectToSlot);
}
EmitSignal emitSignalObject;
public slots:
void connectToSlot() {
qDebug() << "Connected";
}
};
As you can see, I tried to connect the signal and slot, but it seems like the slot is not triggered. And the only output I got is: Signal emitted.
Why isn't the slot not connected and how do I do it properly?
Thanks

You are emitting a signal from EmitSignal's constructor. That constructor will run before the body of ConnectSlot's constructor begins execution.
So the signal will be emitted before the connection is made.
You need to change your code so that connections are made before signals get fired.

Related

connect multiple signal to a slot

I've the follwoing issue.
There are two signals :
void buttonChanged(int);
void pulseWidthValue(int);
buttonChanged is emitted from a slot nextBtn:
void Program::nextBtn()
{
m_currentBtn++;
if(m_currentBtn > btnGrp->buttons().size())
{
m_currentBtn = 0;
phaseOver = true;
saveToXMLFile();
}
emit buttonChanged(m_currentBtn);
}
it's connected as follows:
connect(ui->btn_nextPhase, &QPushButton::clicked, this, &Program::nextBtn);
connect(this, &Program::buttonChanged, this, &Program::paintBtn);
the signal, buttonChanged is used in another slot to paint button:
void Program::paintBtn(int id) // how do I change the def of this function to receive to signal?
{
if(id==1)
{
ui->btn1->setStyleSheet(StyleSheetOn);
ui->btn2->setStyleSheet(StyleSheetOff);
ui->btn3->setStyleSheet(StyleSheetOff);
}
else if(id==2)
{
ui->btn1->setStyleSheet(StyleSheetOff);
ui->btn2->setStyleSheet(StyleSheetOn);
ui->btn3->setStyleSheet(StyleSheetOff);
}
else if(id==3)
{
ui->btn1->setStyleSheet(StyleSheetOff);
ui->btn2->setStyleSheet(StyleSheetOff);
ui->btn3->setStyleSheet(StyleSheetOn);
}
else
{
ui->btn1->setStyleSheet(StyleSheetOff);
ui->btn2->setStyleSheet(StyleSheetOff);
ui->btn3->setStyleSheet(StyleSheetOff);
}
ui->label_7->setText(QString::number(pw_value)); // this pw_value is from the other signal pulseWidthValue
}
the basic idea is , there are 3 phase buttons , clicking Next will switch between these buttons and change its color. Now I need to use the other signal pulseWidthValue inside paintBtn
Now I come to the question:
How do I connect two signals, buttonChanged and pulseWidthValue, (both signals are coming from different functions) to the paintBtn slot?
Qt allows you to connect multiple times even to the same slots. It even allows you to connect between signals.
Check this example, is not meant to be functional but descriptive enought to see many options and accesability.
class A:public QObject
{
Q_OBJECT
...
signals:
void signalA1();
void signalA2(const QString &);
}
class B:public QObject
{
Q_OBJECT...
signals:
void signalB();
public slots:
void slotB();
}
class C:public QObject
{
...
public:
C(QObject *parent):QObject(parent)
{
a=new A(this);
b=new B(this);
}
void connectionTest()
{
connect (a,&A::signalA1,b,&B::slotB) ; // one connection to slot B::slotB
connect (this,&C::signalC,b,&B::slotB); // another connection to B::slotB
connect (a,&A::signalA1,this,&C::slotC) ; // another connection from A::signalA, slotC is private so only I can connect
connect (b,&B::signalB,this,&C::signalC); // connection from signal to signal
connect (a,&A::signalA2,this,&C::slotC); //connection from A::signalA2 to C::slotC
//with different argument count, but compatible as slotC doesn't need an argument
connect (a,&A::signalA1,b,&B::slotB) ; // duplicate connection to slot B::slotB (signalA1 will trigger slotB two times)
}
signals:
void signalC();
private slots:
void slotC();
private:
class A *a;
class B *b;
}

How to connect signal and slot in different classes in Qt?

I have two simple classes(class A and class B).
In a.h, I just declared a QPushButton:
QPushButton *testBtn = new QPushButton(this);
In b.h:
class B : public QMainWindow
{
Q_OBJECT
public:
explicit B(QWidget *parent = nullptr);
A testingA;
public slots:
void testing();
};
and b.cpp:
B::B(QWidget *parent) : QMainWindow(parent)
{
connect(testingA.testBtn, &QPushButton::clicked, this, &B::testing);
}
void B::testing()
{
qDebug() << "testing";
}
I am trying to connect the signal in class A to the slot in class B, but from the code I provide, it's not working.
So what is the right way to do it? Thanks
Edit:
According to PRIME's answer, I made a few changes.
In A's constructor, added:
connect(testBtn, &QPushButton::clicked, [this](){OnButtonClicked();});
to emit the own defined OnButtonClicked() signal;
and in B's construtor, changed to this:
connect(&testingA, &A::OnButtonClicked, this, &B::testing);
But when I clicked the button, the testing slot still not triggered.
Edit 2:
After doing some researches and trying a few times, I found that if I created B's object in A's constructor, and then connect A's signal to B's slot in A, it will work.
But I really can not figure out why I can not connect A's signal to B's slot in B.
This is what's in the main.cpp:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
B b;
A w;
w.show();
return a.exec();
}
Is that because of some reasons that A's object is out of scope in B?
Can someone tell me where I did wrong? Thanks so much.
Don't do it like this, hide your button in the class A, emit your own defined signal from class A lets call it OnButtonClicked.
Cascading code(inside A's c'tor):
connect(testBtn , &QPushButton::clicked, [this](){OnButtonClicked();});
You will also have to declare this new signal in class A now:
So class A must have folowing besides whatever it has right now:
class A
{
Q_OBJECT
signals:
void OnButtonClicked();
};
No special slot is needed since you are using a Lambda as a slot for the signal OnButtonClicked.
Connection in class B( do it in the c'tor ):
connect(testingA, &A::OnButtonClicked, this, &B::testing);
You can connect signal-to-signal in your sender object, for example widget containing the button:
class MyWidget : public QWidget
{
Q_OBJECT
QPushButton *pushButton;
public:
explicit MyWidget(QWidget *parent = nullptr) : QWidget(parent), pushButton(new QPushButton(this)) {
connect(pushButton, &QPushButton::click, this, &MyWidget::buttonClicked);
}
signals:
void buttonClicked();
public slots:
};
By the way you would normally send signals by using emit keyword, e.g.:
emit buttonClicked();
Then the consumer:
class TestObject : public QObject
{
Q_OBJECT
public:
explicit TestObject(QObject *parent = nullptr) : QObject(parent) { }
public slots:
void onButtonClicked() {
qDebug() << "clicked";
}
};
And connect both instances:
MyWidget widget;
TestObject to;
QObject::connect(&widget, &MyWidget::buttonClicked, &to, &TestObject::onButtonClicked);
in your class A you should use the signal testing of the class B, if you clicked on your button the OnButtonClicked function will be activated
A:
public slots:
void OnButtonClicked();
void A::OnButtonClicked()
{
...
emit testing(1);
}
B:
signals:
void testing(int level);
then to connect both you can do this
connect(startButton, &QPushButton::clicked, board, &A::OnButtonClicked);

Qt Passing signal from Item to a container

I have a QVector of pointers to type X, whose items, i.e. X's own QProcesses. These processes can terminate at arbitrary time. Now, I have constructed signal-slot connection inside class X when a process ends. However, I want to propagate it to the handler class which has a QVector of X* as a member. What is an elegant way for doing this?
You can connect a signal to a signal, hiding the source signal being an implementation detail:
class MyInterface : public QObject {
Q_OBJECT
...
QProcess m_process;
public:
Q_SIGNAL void processEnded();
MyInterface(QObject * parent = 0) : QObject(parent) {
connect(&QProcess, &QProcess::finished, this, &MyInterface::processEnded);
...
}
};
The handler class can listen to these signals and do something with them.
class Handler : public QObject {
Q_OBJECT
QVector<MyInterface*> m_ifaces; // owned by QObject, not by the vector
void addInterface(MyInterface* ifc) {
ifc->setParent(this);
connect(ifc, &MyInterface::processEnded, this, [this, ifc]{
processEnded(ifc);
});
m_ifaces.append(ifc);
}
void processEnded(MyInterface* ifc) {
// handle the ending of a process
...
}
...
};

QT signal with struct in parameter

I have the class :
class SupervisionManager : public QThread {
Q_OBJECT public:
explicit SupervisionManager(ComAds* com, ComRegEtat* comEt,
ComRegOrdonnanceur* comOrdo,
QObject *parent = 0);
~SupervisionManager();
protected:
virtual void run();
private:
void actionFromPlc();
ComRegEtat::Antichoc antichoc;
signals:
void majAntichoc(ComRegEtat::Antichoc&);
};
and the implementation:
void SupervisionManager::run() {
manage=true;
while(manage)
{
actionFromPlc();
usleep(5000);
}
}
void SupervisionManager::actionFromPlc() {
antichoc.SAS = false;
emit majAntichoc(antichoc);
}
And I connect this signal with :
connect(manager, SIGNAL(majAntichoc(ComRegEtat::Antichoc&)),
preparation, SLOT(affichageAntichoc(ComRegEtat::Antichoc&)));
How do to emit a signal with a struct in its parameter list?
I think I have to use a QSignalMapper but I don't understand how.
In absolutely same way as you emit other things..
ComRegEtat::Antichoc myStruct;
.. some initialisation code
emit majAntichoc(myStruct);
I dont know for sure about latest Qt (after they changed signals/slot be templates based), but before 'emit' was just empty define, so you should look on emit like on function call...
With my code, the slot isn't called whereas the signal is emitted.
I found the solution :
signals:
void majAntichoc(ComRegEtat::Antichoc *);
and
slot :
void affichageAntichoc(ComRegEtat::Antichoc *);
And I don't have to use a QSignalMapper.
Thanks

Signal-slot doesn't work using QThread

I am using QT framework. I have been using SIGNAL-SLOT for a while. I like it. :-)
But I cannot make it work when I use QThread. I always create new thread using “moveToThread(QThread …)” function.
Any suggestion? :-)
The error message is:
Object::connect: No such slot connection::acceptNewConnection(QString,int) in ..\MultiMITU600\mainwindow.cpp:14
Object::connect: (sender name: 'MainWindow')
I have read about similar problems but those were not connected to QThread.
Thanks, David
EDITED: you asked for source code
Here is one:
Here is the code:
The main class which contains the signal and the new thread:
mainwindow header:
class MainWindow : public QMainWindow
{
…
QThread cThread;
MyClass Connect;
...
signals:
void NewConnection(QString port,int current);
…
};
The constructor of the above class: .cpp
{
…
Connect.moveToThread(&cThread1);
cThread.start(); // start new thread
….
connect(this,SIGNAL(NewConnection(QString,int)),
&Connect,SLOT(acceptNewConnection(QString,int))); //start measuring
…
}
The class that contains the new thread and SLOT
Header:
class MyClass: public QObject
{
Q_OBJECT
….
public slots:
void acceptNewConnection(QString port, int current);
}
And the .cpp file of the above class:
void MyClass::acceptNewConnection(QString port, int current){
qDebug() << "This part is not be reached";
}
Finally I use emit in the class where the connection was made:
void MainWindow::on_pushButton_3_clicked()
{
…
emit NewConnection(port, 1);
}
class MyClass : public QObject
{
Q_OBJECT
public:
explicit MyClass(QObject *parent = 0);
public slots:
void acceptConnection(QString port, int current) {
qDebug() << "received data for port " << port;
}
};
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0) : QMainWindow(parent) {
myClass.moveToThread(&thread);
thread.start();
connect(this, SIGNAL(newConnection(QString,int)), &myClass, SLOT(acceptConnection(QString,int)));
emit newConnection("test", 1234);
}
signals:
void newConnection(QString, int);
private:
QThread thread;
MyClass myClass;
};
output:
received data for port "test"
Is your void MainWindow::on_pushButton_3_clicked() slot connected to a signal?
Also, for the sake of the clarity and readability of your code, keep the established naming convention and use lower case for object instances and member objects and methods.

Resources