How to add slots between child and parent classes? - c++

I am trying to connect signals send by buttons in one class with slots of both child and parent classes. Here is an example that reproduces the problem:
ErrorClass.cpp
#include "errorclass.h"
ErrorClass::ErrorClass(QPushButton *button) : QObject()
{
this->button = button;
}
void ErrorClass::makeConnectHappen()
{
connect(button, SIGNAL(pressed()), this, SLOT(exampleSlot()));
}
//SLOT
void ErrorClass::exampleSlot()
{
qDebug() << "ExampleSlot was here";
}
ErrorClassChild.cpp
#include "errorclasschild.h"
ErrorClassChild::ErrorClassChild(QPushButton *button) : ErrorClass(button)
{
makeConnectHappen();
}
void ErrorClassChild::makeConnectHappen()
{
ErrorClass::makeConnectHappen();
connect(button, SIGNAL(released()), this, SLOT(exampleChildSlot()));
}
//SLOT
void ErrorClassChild::exampleChildSlot()
{
qDebug() << "exampleChildSlot was here";
}
and finally standard MainWindow.cpp with a QPushButton
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "errorclasschild.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
ErrorClassChild ecc(ui->pushButton);
}
MainWindow::~MainWindow()
{
delete ui;
}
Where makeConnectHappen() is a virtual function in ErrorClass.h which is inherited and expanded by ErrorClassChild. I hope this will be clear.
When I compile and run the program there is Apllication Message
QObject::connect: No such slot ErrorClass::exampleChildSlot() in ../QListWidgetProblem/errorclasschild.cpp:11
QObject::connect: (sender name: 'pushButton')
Now, when I put exampleChildSlot() in the parent as a pure virtual slot the error disappears but no qDebug() message is shown.
How make the connect with parents and children slots at the same time? Or is my idea completaly wrong?

Q_OBJECT is not a property, it is a macro, so it is cannot be inherited. So if you would like to use signals-slots in your class (even if it is derived from class, where Q_OBJECT already is), you should add it to your class. There already was discussion on this topic here , so it could help you.

You should rather use a virtual slot (the Qt doc explicitely say they can be virtual) :
Put these declarations in your base class
class ErrorClass : public QObject{
Q_OBJECT
//...
void makeConnectHappen();
public slots:
virtual void exampleSlot();
}
Then, implement makeConnectHappen() for the base class exactly the way you did, and you'll only have to reimplement the slot in the derived class. Then, when the button will emit the pressed() signal, it will trigger the correct slots depending on the class of the objects you instantiated with this button.

Related

QPushButton signal

I'm trying to get a QPushButton's action method running doing the following.
My login.h:
//
// Created by simon on 28.04.22.
//
#ifndef RESTCLIENT_LOGIN_H
#define RESTCLIENT_LOGIN_H
#include <QWidget>
#include <QPushButton>
#include <QLineEdit>
QT_BEGIN_NAMESPACE
namespace Ui { class Login; }
QT_END_NAMESPACE
class Login : public QWidget {
Q_OBJECT
QPushButton * loginButton;
QLineEdit * passwordInput;
QLineEdit * usernameInput;
QObject::connect(loginButton, &QPushButton::click, this, &buttonPressed);
public slots:
void buttonPressed();
public:
explicit Login(QWidget *parent = nullptr);
~Login() override;
private:
Ui::Login *ui;
};
#endif //RESTCLIENT_LOGIN_H
The corresponding login.cpp:
#include "login.h"
#include "ui_Login.h"
Login::Login(QWidget *parent) :
QWidget(parent), ui(new Ui::Login) {
ui->setupUi(this);
}
Login::~Login() {
delete ui;
}
void Login::buttonPressed() {
//todo process login
}
The build fails, and Clion marks the code line containing the connect method in red. I'm aware that my attempt to connect the signal to my function is wrong, I hope someone can help me.
The issue is that QPushButton::click() is not a signal, it is a function that performs a click.
The signal emitted when clicking the button is: QPushButton::clicked().
And as already mentioned, you should call the QObject::connect() function from inside a function (in the constructor for example). It makes no sense to call it in the class declaration.
The connect call looks mostly fine, except that click is not a signal as Fareanor first noticed in his answer; use the clicked signal from QPushButton's base class QAbstractButton instead. See also QAbstractButton Signals for all available signals.
Additionally, connect needs to be inside of a function, not in the class declaration. The button needs to be initialized for the connection to work, so the constructor of your Login class seems like a logical place for it, for example:
Login::Login(QWidget *parent) :
QWidget(parent), ui(new Ui::Login) {
ui->setupUi(this);
QObject::connect(loginButton, &QPushButton::clicked, this, &buttonPressed);
}
From the code you're showing it seems that loginButton is separate from the other GUI stuff in ui, so you probably also need to create that button first, i.e., adding , loginButton(new QPushButton) after ui(...), or move the loginButton to your .ui file...

Can't bind signal to slot in my Qt application

I'm new to Qt and I have a very simple demo app. It just include a QLineEdit widget and I want to invoke a function test() when I press ctrl+p in the QLineEdit.
Below are the related files.
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <QShortcut>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
QShortcut *s = new QShortcut(QKeySequence("Ctrl+P"), ui->lineEdit);
connect(s, SIGNAL(activated()), ui->lineEdit, SLOT(test()));
}
MainWindow::~MainWindow()
{
delete ui;
}
void test(){
qDebug() << "test() triggered!" << endl;
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
void test();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
When I compile the application, I saw below messages in the debug panel and the application didn't respond to ctrl+p.
QObject::connect: No such slot QLineEdit::test() in ..\ShortcutIssueDemo\mainwindow.cpp:13
QObject::connect: (receiver name: 'lineEdit')
What's the problem with it?
You have 2 misconceptions:
The connection indicates the link between the object that emits the signal, the signal, the object to which the slot belongs and the slot. In your case it is obvious that the object to which the slot "slot" belongs is this.
If the old syntax (SIGNAL & SLOT) is to be used then "test" must be declared as slot.
So for the above there are 2 possible solutions:
Change to :
connect(s, SIGNAL(activated()), this, SLOT(test()));
public slots:
void test();
Or use new syntax:
connect(s, &QShortcut::activated, this, &MainWindow::test);
Between both solutions, the second one is better since it will indicate errors in compile-time instead of silent errors in run-time.
By default, the context of the shortcut is Qt::WindowShortcut, that is, it will fire when the key combination is pressed and the window has focus, if only when QLineEdit has focus then you have to change the context to Qt::WidgetShortcut:
s->setContext(Qt::WidgetShortcut);
You have received the error message saying there is no such slot...
Note that u haven't marked test() as slot, hence in <mainwindow.h>, replace
void test();
by
public slots: void test();
And the slot test() belongs to the mainwindow not to s, hence use this instead of s

Can't conect two frames with custom signals

I'm trying to connect two frames with a custom signal but I'm not really getting it.
This code is just an example of what im trying to do in my program, my objective is to transfer data between frames.
Files:
(sender)
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
signals:
void send();
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
private slots:
void on_pushButton_clicked();
};
#endif // MAINWINDOW_H
On "mainwindow.cpp" I've got the void on_pushButton_clicked() that emits the signal and shows the new frame:
private slot void:
void MainWindow::on_pushButton_clicked()
{
emit send();
Dialog sw;
sw.setModal(true);
sw.exec();
}
(receiver):
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include <QDebug>
namespace Ui {
class Dialog;
}
class Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = nullptr);
~Dialog();
private slots:
void receive();
private:
Ui::Dialog *ui;
int a;
};
#endif // DIALOG_H
and the .cpp:
#include "dialog.h"
#include "ui_dialog.h"
#include "mainwindow.h"
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
a=0;
MainWindow w;
connect(&w, SIGNAL(send()), this, SLOT(receive()));
qDebug() << a;
}
Dialog::~Dialog()
{
delete ui;
}
void Dialog::receive(){
qDebug() << "ola";
a++;
}
Conclusion:
So basicly the function Dialog doesn't print the qDebug(), and 'a' is still 0, so I conclude that the connection isn't set/executed.
Thanks all,
Best regards,
Dylan Lopes.
edit: Wrote a conclusion on the end of the post.
Consider the code in your Dialog constructor...
MainWindow w;
connect(&w, SIGNAL(send()), this, SLOT(receive()));
This creates a locally scoped MainWindow on the stack and connects its send() signal to the Dialog's receive() slot. But the MainWindow -- and, hence, the connection -- will be destroyed as soon as the Dialog constructor has completed.
In addition, looking at MainWindow::on_pushButton_clicked...
void MainWindow::on_pushButton_clicked()
{
emit send();
Dialog sw;
sw.setModal(true);
sw.exec();
}
You emit the send() signal before constructing the Dialog.
I don't really know enough about what you're trying to achieve to provide a definitive answer, but in the interests of getting some kind of signal/slot interaction you might want to do the following: change the Dialog constructor to...
Dialog::Dialog(QWidget *parent)
: QDialog(parent)
, ui(new Ui::Dialog)
{
ui->setupUi(this);
a=0;
qDebug() << a;
}
And change MainWindow::on_pushButton_clicked to...
void MainWindow::on_pushButton_clicked()
{
Dialog sw;
connect(this, &MainWindow::send, &sw, &Dialog::receive);
emit send();
sw.setModal(true);
sw.exec();
}
That should at least result in Dialog::receive being invoked and you can work from there.
Connection between a signal and a slot doesn't mean that the signal function will be triggered.
You still need to emit your signal so that a gets updated.
Creating an empty slot isn't working either, as slots are the receiving point of a signal. In this case, on_pushButton_clicked() gets triggered whent he push button is clicked. This doesn't trigger send unless you call EMIT(send()) (IIRC, you emit a signal with EMIT, is that still the case?).

How to know child Window is destroyed form parent Window

I have a parent-child window in my Qt application. Parent class is a QDialog named A and child class is QMainWindow named B. Now I want that whenever B is closed through the 'X' button a signal is to be emitted which can be caught by a slot in class A through which I want certain functionality to be implemented. Is there a predefined signal in Qt I can use?
I want something like this:
B *b=new B;
//some code
connect(b,SIGNAL(destroyed()),this,&A::doSomething);
B also has a QWidget which I can use to detect the destroyed signal. How do I implement this? Do I need to emit a custom signal from ~B() ?
Edit: I don't want to destroy the object b as this would require a reallocation when I want to recreate the window B from A and I want to keep the parameters of b.
Your solution would only work if you set a Qt::WA_DeleteOnClose attribute to your B widget:
b->setAttribute(Qt::WA_DeleteOnClose);
Another option would be to reimplement close event and emit a custom signal there.
Connect your object like this:
widget = new QWidget();
//widget->show(); //optional using
connect(widget, &QWidget::destroyed, this, &MainWindow::widgetDestroy);
widget->setAttribute(Qt::WA_DeleteOnClose);
.cpp :
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButtonNew_clicked()
{
widget = new QWidget();
widget->show();
connect(widget, &QWidget::destroyed, this, &MainWindow::widgetDestroy);
widget->setAttribute(Qt::WA_DeleteOnClose);
}
void MainWindow::on_pushButtonDel_clicked()
{
delete widget;
}
void MainWindow::widgetDestroy()
{
qDebug()<< "deleted."; //after destroy widget this function calling.
}
.h :
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QWidget>
#include <QDebug>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void widgetDestroy();
void on_pushButtonNew_clicked();
void on_pushButtonDel_clicked();
private:
Ui::MainWindow *ui;
QWidget *widget;
};
#endif // MAINWINDOW_H
.ui :

Qt slot connection not working under child Dialog

I have a text editor like program which is a QMainWindow inherited class. There, when I click Find, the connection,
connect(actionFind,SIGNAL(triggered()),this,SLOT(actionFindTriggered()));
Activates. And the defination of that function is
void MainWindow::actionFindTriggered() {
new Find(this);
}
My Find class is
class Find : public QDialog, public Ui::Dialog
{
public:
Find(QWidget *parent=0);
private:
Ui::Dialog *ui;
public slots:
void buttonFindTriggered();
};
And the definition is
Find::Find(QWidget *parent)
: QDialog(parent)
{
ui = new Ui::Dialog;
ui->setupUi(this);
show();
this->
connect(ui->buttonClose, SIGNAL(clicked()), this, SLOT(close()));
connect(ui->buttonFind, SIGNAL(clicked()), this, SLOT(buttonFindTrigddgered()));
}
void Find::buttonFindTriggered() {
qDebug() << "FIND ACTIVATED";
}
What is the problem
When I clicked find from the main window, find window works successfully but could not make the connection. And I get the following msg on console,
Object::connect: No such slot QDialog::buttonFindTriggered() // Edited
Object::connect: (sender name: 'buttonFind')
Object::connect: (receiver name: 'Dialog')
Edited due to a typo...!
You forgot the Q_OBJECT macro.
Also - consider using this notation for getting slot auto-connection (setupUI will automatically connect these slot for you).
void on_buttonFind_clicked();
void on_buttonClose_clicked();
As the error message states, it can't find the slot:
buttonFindTrigddgered()
because it should be:
buttonFindTriggered()