Signal to it's own instance doesn't work - c++

I connected the clicked(bool) event from QPushButton to a private slot mySlot() of my own Widget. But the slot is never called (I placed a breakpoint in mySlot()). I'm using c++ and Qt5.
I wrote a minimal version of my code:
MyLayout.h
class MyLayout : public QWidget
{
Q_OBJECT
public:
MyLayout(QWidget* parent = NULL);
private:
QPushButton *next;
private slots:
void mySlot();
}
MyLayout.cpp
MyLayout::MyLayout(QWidget* parent) : QWidget(parent)
{
next = new QPushButton("Next Step");
QObject::connect(next, SIGNAL(clicked(bool)), this, SLOT(mySlot()));
}
void MyLayout::mySlot() { /* do something */ }
Any ideas?

You created a parentless button and never showed it. Start by giving it parent (this), so it gets shown together with your widget:
next = new QPushButton("Next Step", this);
Then learn how to use layouts.

Related

How to use QGroupBox and QCheckBoxes to one check another?

I'm trying to understand how to use signals to when one QCheckBox be checked it uncheck all other checkboxes present in the same QGroupBox
class GroupBox : public QGroupBox
{
public:
GroupBox(QWidget *parent = nullptr) : QGroupBox(parent)
{
}
public slots:
void uncheck();
};
class CheckBox : public QCheckBox
{
public:
CheckBox(QWidget *parent = nullptr) : QCheckBox(parent)
{
connect(this, SIGNAL(checked()), this, SLOT(checked()));
}
public slots:
void checked()
{
qDebug() << "checked";
}
};
When I click on one of the checkboxes it didn't go to the function checked().
QCheckBox inherits from QAbstractButton
You should use clicked or stateChanged signal instead of checked.
e.q.
connect(this, SIGNAL(stateChanged(int)), this, SLOT(checked(int)));
Btw; if using a modern Qt version, you should ditch the SIGNAL and SLOTS macros and instead use the new connect() syntax that's checked at compile time.
Refer: New Signal Slot Syntax
e.p.
connect(this, &QCheckBox::clicked, this, &CheckBox::checked);

How to detect that the close button of QWidget is pressed?

I create a new QWidget object and I want to know when the close button is pressed.
I have tried the following code:
pWindow = new QWidget();
connect(pWindow , SIGNAL(triggered()), this, SLOT(processCloseButtonWindowsClicked()));
but it give an error:
no signal triggered of pWindow
How to achieve this?
Cause
QWidget does not have a triggered signal.
Solution
I would suggest you to:
Subclass QWidget and reimplement QWidget::closeEvent
Check QEvent::spontaneous to differentiate between a click of the close button and the call to QWidget::close
According to your app's logic either call QWidget::closeEvent(event); to close the widget, or QEvent::ignore to leave it open
Example
I have prepared an example for you of how to implement the proposed solution:
#include <QMainWindow>
#include <QCloseEvent>
#include <QPushButton>
class FooWidget : public QWidget
{
Q_OBJECT
public:
explicit FooWidget(QWidget *parent = nullptr) :
QWidget(parent) {
auto *button = new QPushButton(tr("Close"), this);
connect(button, &QPushButton::clicked, this, &FooWidget::close);
resize(300, 200);
setWindowTitle("Foo");
}
protected:
void closeEvent(QCloseEvent *event) override {
if (event->spontaneous()) {
qDebug("The close button was clicked");
// do event->ignore();
// or QWidget::closeEvent(event);
} else {
QWidget::closeEvent(event);
}
}
};
class MainWindow : public QMainWindow
{
Q_OBJECT
FooWidget *pWindow;
public:
explicit MainWindow(QWidget *parent = nullptr) :
QMainWindow(parent),
pWindow(new FooWidget()) {
pWindow->show();
}
};
void QWidget::closeEvent(QCloseEvent *event) will be the possible way I would go with.
You can read the documentation here.
Before, check if Qt has a class for what you want to do. Maybe you want to use QDialog instead of QWidget for what you want to achieve.
The following code: suppose you want to delete the widget when the X is clicked and you just want to know when to do something.
Try connecting the signal from the base class QObject of your widget when it is Destroyed:
-Your Widget
-attribute setted to destroy your widget after X(closebotton is clicked) or the close() handler is triggered
-connect the destroyed() signal to whatever slot you want to do something before it is destroyed
pWindow = new QWidget();
pWindow->setAttribute(Qt::WA_DeleteOnClose,true);
connect(pWindow , SIGNAL(destroyed()), this,SLOT(processCloseButtonWindowsClicked()));
for more info:
https://doc.qt.io/qt-5/qwidget.html#close
https://doc.qt.io/qt-5/qobject.html#destroyed

QT: simple text from QLineEdit to QLabel of different class

I'm trying to write a very basic program. The main window contains a label. Pressing the "Add New" button opens a QDialog with a QLineEdit. Changing the text, press "Add" and I would like the QLabel in the main window to be updated with the text from QLineEdit. I can get the signals through but the label is not updating. I understand that connect only works on instances of classes, not classes themselves. The problem seems to be the one class is not aware of the instance of the main window.
What I've tried to do is once the Add button is pressed, a signal is emitted. Once that signal is emitted, the slot in the mainWindow class receives a string to use in QLabel::setText().
I've read countless examples and documentation but the examples seem to be too different from the simple task I'm lost in. Any help is appreciated.
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QtWidgets>
#include <QLabel>
class QLineEdit;
class QPushButton;
class QLabel;
class addDlg : public QDialog{
Q_OBJECT
public:
addDlg(QWidget *parent = 0);
signals:
void textChanged(const QString &text);
private slots:
void sendText(QWidget *parent);
private:
QPushButton *addButton;
QLineEdit *inputText;
};
class mainWindow : public QWidget{
Q_OBJECT
public:
mainWindow();
QLabel *textLabel;
public slots:
void recvText(const QString &text);
private slots:
void addDlgShow();
private:
QPushButton *addWindow;
addDlg *dialog;
};
#endif // MAINWINDOW_H
MainWindow.cpp
addDlg::addDlg(QWidget *parent)
: QDialog(parent){
inputText = new QLineEdit(tr("enter here"));
addButton = new QPushButton(tr("Accept"));
QVBoxLayout *vLayout = new QVBoxLayout;
vLayout->addWidget(inputText);
vLayout->addWidget(addButton);
setLayout(vLayout);
setWindowTitle(tr("Add new text"));
connect(addButton, SIGNAL(clicked()),
this, SLOT(sendText()));
}
void addDlg::sendText(){
QString text = inputText->text();
emit textChanged(text);
// This connect is where I believe the problem lies.
connect(this, SIGNAL(textChanged(QString)),
mainPtr, SLOT(recvText(QString)));
//mainPtr is uninitialized as I can't seem to point it to the manWindow instance
//I can do mainWindow* mainPtr = new mainWindow but that just creates a new instance.
//How do I pass on the first mainWindow main instance "mainPtr" to this class addDlg?
}
mainWindow::mainWindow()
: QWidget(0){
textLabel = new QLabel(tr("Empty"));
addWindow = new QPushButton(tr("Add New"));
dialog = new addDlg();
QVBoxLayout *vLayout = new QVBoxLayout;
vLayout->addWidget(textLabel);
vLayout->addWidget(addWindow);
setLayout(vLayout);
setWindowTitle(tr("Test 4"));
connect(addWindow, SIGNAL(clicked()),
this, SLOT(addDlgShow()));
}
void mainWindow::addDlgShow(){ dialog->show(); }
void mainWindow::recvText(const QString &text){
QString input = text;
textLabel->clear();
textLabel->setText(input);
textLabel->update();
}
One solution is to put your connect code in mainWindow::mainWindow where you have pointers to both the mainwindow and your newly created dialog. The snippet might change to this:
mainWindow::mainWindow() : QWidget(0) {
// ... existing code ..
// add this
connect(dialog, SIGNAL(textChanged(QString)),
this, SLOT(recvText(QString)));
}

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()

Qt, can't display child widget

I have two widgets defined as follows
class mainWindow : public QWidget
{
Q_OBJECT
public:
mainWindow();
void readConfig();
private:
SWindow *config;
QVector <QString> filePath;
QVector <QLabel*> alias,procStatus;
QVector <int> delay;
QGridLayout *mainLayout;
QVector<QPushButton*> stopButton,restartButton;
QVector<QProcess*> proc;
QSignalMapper *stateSignalMapper, *stopSignalMapper, *restartSignalMapper;
public slots:
void openSettings();
void startRunning();
void statusChange(int);
void stopProc(int);
void restartProc(int);
void renew();
};
class SWindow : public QWidget
{
Q_OBJECT
public:
SWindow(QWidget *parent=0);
void readConfig();
void addLine(int);
private:
QVector<QPushButton*> selectButton;
QVector<QLabel*> filePath;
QVector<QLineEdit*> alias;
QSignalMapper *selectSignalMapper;
QVector<QSpinBox*> delay;
QGridLayout *mainLayout;
public slots:
void selectFile(int);
void saveFile();
void addLineSlot();
};
when i create and display SWindow object from mainWindow like this
void mainWindow::openSettings()
{
config = new SWindow();
config->show();
}
everything is ok, but now i need to access the mainWindow from SWindow, and
void mainWindow::openSettings()
{
config = new SWindow(this);
config->show();
}
doesn't display SWindow. How can i display SWindow?
How do i call a function on widget close?
By default a QWidget isn't a window. If it is not a window and you specify a parent, it will be displayed inside the parent (so in your case it is probably hidden by other widgets inside your mainWindow).
Look at windowFlags() too. Or you could make your SWindow inherit from QDialog, depending on what you use it for.
As for calling a function on widget close : you could reimplement closeEvent().
When you do config = new SWindow(this); you're setting the parent of config to be the instance of mainWindow.
This means config is no longer a top-level widget, therefore it won't display outside the mainWindow instance (specifically, it would need to be the central widget or inside the mainWindow instance's layout to be displayed).
EDIT: Sorry - I missed your last question; How do i call a function on widget close
You will want to override the QWidget::closeEvent(QCloseEvent *event) method. This gets called when you close a top-level widget. The most practical thing to do is emit() a signal so that another class can handle it having been closed.
As noted by Leiaz, you can use the windowsFlags flag when you create the widget. It would look like this:
void mainWindow::openSettings()
{
config = new SWindow(this, Qt::window);
config->show();
}
To reimplement the closeEvent:
header:
protected:
virtual void closeEvent ( QCloseEvent * event )
cpp:
void sWindow::closeEvent(QCloseEvent *event)
{
this->parentWidget()->SomeFunction();
qWidget::closeEvent(event);
}
However, its probably better to use signal/slots for your case here. Since you said you want to call the parent's renew method on some button click in sWindow, what you want is to EMIT a signal everytime the button is clicked, and connect this signal in the parent with the parent's refresh slot.
void sWindow::sWindow()
{
...
connect(ui.button, SIGNAL(clicked()), this, SLOT(btnClicked()));
}
void sWindow::btnClicked()
{
// whatever else the button is supposed to do
emit buttonClicked();
}
and in your parent class
void mainWindow::openSettings()
{
config = new SWindow(this, Qt::window);
connect(config, SIGNAL(buttonClicked()), this, SLOT(refresh()));
config->show();
}