How to connect signal and slot in different classes in Qt? - 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);

Related

How can I connect a signal to QWidget::update slot?

I am using Qt5 with new signal/slot syntax.
I don't know why the following code doesn't work:
QWidget *widget = new QWidget();
connect(pipeline, &Pipeline::NewFrame, widget, &QWidget::update);
I get the error:
no matching member function for call to 'connect' why?
Pipeline class inherits from QObject and NewFrame signal has the same signature as QWidget::update
class Pipeline
: public QObject
{
Q_OBJECT
Q_DISABLE_COPY(Pipeline)
public:
Pipeline(QObject *parent);
signals:
void NewFrame();
};
I am using QtCreator on Arch Linux with g++.
TL;DR: The pipeline should be signaling an image, and the widget should have a SetImage method:
class Pipeline : public QObject {
Q_OBJECT // important
public:
Q_SIGNAL void NewFrame(const QImage &);
...
};
class Viewer : public QWidget {
Q_OBJECT // important
QImage m_image;
public:
Q_SLOT void SetImage(const QImage &image) {
m_image = image;
update();
}
...
};
This is how you'd be using it - note that Viewer knows nothing about Pipeline, because it shouldn't: it just shows new frames, wherever they come from.
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
Pipeline pipeline;
Viewer viewer;
QObject::connect(&pipeline, &Pipeline::NewFrame, &viewer, &Viewer::SetImage);
return app.exec();
}
Connecting anything to QWidget::update directly, especially from external sources, is usually a sign of bad design.
To satisfy your curiosity, you can use a lambda or qOverload to specify what you're connecting to, to fix the very error you're seeing - caused by ambiguity of the the type of the method pointer. Any of the following will work:
connect(…, widget, qOverload<>(&QWidget::update));
or
auto constexpr update = qOverload<>(&QWidget::update));
connect(…, widget, update);
or
connect(…, widget, [widget]{ widget->update(); });

How can I use replacedlg.ui in mainwindow.cpp?

I have written a project which includes a mainwindow and a replacedlg.ui. I want to use replacedlg.ui in mainwindow.cpp.
I'd like to write things like ui->button in mainwindow.cpp, but I can't.
Who can help me make this work?
The whole project is here.
Don't try to share the ui variable between classes. It is bad design. Instead add methods in your classes which will let you do what you need to do.
In your case where you want to send the text of your line edit from replaceDlg class to your MainWindow class, you should use signals and slots. Here is an example:
#include <QtWidgets>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = Q_NULLPTR) : QMainWindow(parent)
{
setCentralWidget(&text_edit);
}
public slots:
void addText(const QString &text)
{
text_edit.append(text);
}
private:
QTextEdit text_edit;
};
class Dialog : public QDialog
{
Q_OBJECT
public:
Dialog(QWidget *parent = Q_NULLPTR) : QDialog(parent)
{
setLayout(new QHBoxLayout);
QPushButton *send_button = new QPushButton("Send");
layout()->addWidget(&line_edit);
layout()->addWidget(send_button);
connect(send_button, &QPushButton::clicked, this, &Dialog::sendButtonClicked);
}
signals:
void sendText(const QString &text);
private slots:
void sendButtonClicked()
{
emit sendText(line_edit.text());
accept();
}
private:
QLineEdit line_edit;
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
Dialog d;
QObject::connect(&d, &Dialog::sendText, &w, &MainWindow::addText);
w.show();
d.show();
return a.exec();
}
#include "main.moc"

Qt: How do I notify changing mouse coordinates to parent object

I have a little problem with the Qt class QGraphicsScene:
To detect the current mouse coordinates I made a new class QGraphicsScenePlus with QGraphicsScene as the base class. I have already redefined the slot function mouseMoveEvent(QGraphicsSceneMouseEvent* event) and the received coordinates seem to be correct. Now I want to notify the parent QMainWindow class, where the QGraphicsScenePlus object is stored, whenever the mouse coordinates change. What is the best way to do this? I already tried to define signals and slots, but it didn't work. The slot function wasn't found during the execution of the program.
Here is the code so far:
qgraphicssceneplus.h
#ifndef QGRAPHICSSCENEPLUS_H
#define QGRAPHICSSCENEPLUS_H
#include <QObject>
#include <QGraphicsScene>
#include <QGraphicsSceneMouseEvent>
class QGraphicsScenePlus : public QGraphicsScene {
public:
QGraphicsScenePlus(QObject* parent = 0);
public slots:
void mouseMoveEvent(QGraphicsSceneMouseEvent* event);
public:
int mx = 0;
int my = 0;
};
#endif // QGRAPHICSSCENEPLUS_H
qgraphicssceneplus.cpp
#include "qgraphicssceneplus.h"
QGraphicsScenePlus::QGraphicsScenePlus(QObject* parent) : QGraphicsScene(parent) {
}
void QGraphicsScenePlus::mouseMoveEvent(QGraphicsSceneMouseEvent* mouseEvent) {
mx = mouseEvent->scenePos().x();
my = mouseEvent->scenePos().y();
this->update();
}
Comment
I am not sure how you made the above code compiled.
1. Even though you subclass from a QObject, you still need the Q_OBJECT macro to keep meta-object compiler informed:
class QGraphicsScenePlus : public QGraphicsScene {
Q_OBJECT // <--- You miss this
public:
QGraphicsScenePlus(QObject* parent = 0);
2. It's not allowed to assign primitive value in C++ class definition, do it in the constructor instead:
public:
int mx /*= 0*/;
int my /*= 0*/;
};
Solution
As for your question:
What is the best way to do this? I already tried to define signals and slots, but it didn't work.
The best way is still Signals & Slots.
Code
qgraphicssceneplus.h
class QGraphicsScenePlus : public QGraphicsScene {
Q_OBJECT
public:
QGraphicsScenePlus(QObject* parent = 0);
public slots:
void mouseMoveEvent(QGraphicsSceneMouseEvent* event);
signals:
void sendCoord(int,int); // for sending the information of coordinates
public:
int mx;
int my;
};
qgraphicssceneplus.cpp
QGraphicsScenePlus::QGraphicsScenePlus(QObject* parent) : QGraphicsScene(parent) {
mx = 0;
my = 0;
}
void QGraphicsScenePlus::mouseMoveEvent(QGraphicsSceneMouseEvent* mouseEvent) {
mx = mouseEvent->scenePos().x();
my = mouseEvent->scenePos().y();
emit sendCoord(mx, my); // emit the signal
this->update();
}
To catch the signal, define the slot in QMainWindow. For example:
public slots:
void receiveCoord(int x, int y);
and connect it to the signal of your graphic scene.
Demo

Qt signal-slot confusion

I am working on a project where I am having to create a Qt signal-slot connection from the constructor of a class to the class it's initialized inside. This is how the codes look like. I want both the connection mentioned below to work but from what the output suggests, only connection#1 works. My question is how to make connection#2 work!
class A
class classA :public QWidget{
Q_OBJECT
public:
classA(){
emit this->demoSignalA();
}
signals:
void demoSignalA();
public slots:
void demoSlotA(){qDebug()<<"SIGNAL FROM CLASS B"}
};
Class B
class classB :public QWidget{
Q_OBJECT
public:
classB(){
classA *a = new classA;
connect(this, SIGNAL(demoSignalB()), a, SLOT(demoSlotA())); //WORKS
connect(a, SIGNAL(demoSignalA()), this, SLOT(demoSlotB())); //DOESN'T WORK
emit this->demoSignalB();
}
signals:
void demoSignalB();
public slots:
void demoSlotB(){qDebug()<<"SIGNAL FROM CLASS A";}
};
MAIN
int main(int argc, char *argv[]){
QApplication a(argc, argv);
...
...
classB b; //INVOCATION INITIATED
return a.exec();
}
OUTPUT
SIGNAL FROM CLASS B
If you follow the sequence of the code, it should be clear that at the point where you call
emit this->demoSignalA();
in the first line of the classB constructor, the connection has not yet been made. If the connection has not been made then the slot sill not be executed when you emit the signal.
You should emit both signals after the connections have been made, in the classB constructor.
(As a matter of principle it's probably better not to start emitting signals until you have finished the constructor, but that's not important here)

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