I try to become more familiar with singnals and slots with Qt.
I want to emit a signal in one class and want to handle it at one other.
Here my example code:
main.c
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
class Emiter
{
signals:
void anSignal ();
};
class MainWindow : public QMainWindow
{
Q_OBJECT
private slots:
void handleEmitter ();
public:
MainWindow(QWidget *parent = 0);
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
auto emiter = new Emiter();
connect( emiter,
&Emiter::anSignal,
this,
&MainWindow::handleEmitter );
}
void
MainWindow::handleEmitter()
{
}
Then I get this error:
error: ‘qt_metacall’ is not a member of ‘Emiter’ enum { Value = sizeof(test(&Object::qt_metacall)) == sizeof(int) };
What does this mean?
Signals and slots are available only in QObject derived classes, and a Q_OBJECT macro is needed.
class Emiter : public QObject
{
Q_OBJECT
public:
signals:
void anSignal ();
};
For more detail answer: click here
Another case is if you use multiple inheritances, you need to put QObject as the first parent class.
Related
I have a problem. I created two classes in my Qt project. One as the main window, and second as the settings dialog. My idea is to send the values from "Settings" to "MainWindow" (like from one TextEdit to another) but unfortunately, I have no idea how to do it. It's confusing me. I have read similar topics on the internet but none of them gives me a clear answer. Can someone help me understand the way how can I do it via example?
I have no useful code to place it here, so I will put the part of the source code and headers of mine.
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
[...]
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "settings.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow()
[...]
private:
Ui::MainWindow *ui;
[...]
};
#endif // MAINWINDOW_H
settings.cpp
#include "settings.h"
#include "ui_settings.h"
#include "mainwindow.h"
#include "ui_mainwindow.h"
Settings::Settings(QWidget *parent) :
QDialog(parent),
ui(new Ui::Settings)
{
ui->setupUi(this);
}
settings.h
#ifndef SETTINGS_H
#define SETTINGS_H
#include <QDialog>
namespace Ui {
class Settings;
}
class Settings : public QDialog
{
Q_OBJECT
public:
explicit Settings(QWidget *parent = nullptr);
~Settings();
[...]
private:
Ui::Settings *ui;
[...]
};
#endif // SETTINGS_H
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
Use signals/slots mechanism to share values between two QObject.
For example:
The following code allows yout to send the value in a QLineEdit to another widget by clicking on a button:
class Widget1: public QWidget
{
Q_OBJECT
public:
Widget1(): QWidget(),
message(new QLineEdit())
{
QPushButton* button = new QPushButton("Send msg", this);
connect(button, &QPushButton::clicked, this, [=]() { emit this->sendMsg(message->text());}); // When you click on the button, it will emit the signal sendMsg
QVBoxLayout* layout = new QVBoxLayout(this);
layout->addWidget(message);
layout->addWidget(button);
}
private:
QLineEdit* message;
signals:
void sendMsg(QString const& msg);
};
class Widget2: public QWidget
{
Q_OBJECT
public:
Widget2(): QWidget(),
display(new QLabel("Nothing to display", this))
{
QVBoxLayout* layout = new QVBoxLayout(this);
layout->addWidget(display);
}
private:
QLabel* display;
public slots:
void receive(QString const& message)
{
display->setText(message); // When called, display the message in the label
}
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QWidget* mainWidget = new QWidget();
QHBoxLayout* layout = new QHBoxLayout(mainWidget);
Widget1* w1 = new Widget1();
Widget2* w2 = new Widget2();
layout->addWidget(w1);
layout->addWidget(w2);
// When the signal sendMsg is emitted, call the slot receive
QObject::connect(w1, &Widget1::sendMsg, w2, &Widget2::receive);
mainWidget->show();
return app.exec();
}
There are multiple ways to achieve this.
For example you can provide the public Getter Methods in your dialog for provide value to the public and use them directly in the MainWindow to read those.
Or you can use Signals/Slots as stated above.
One example with Signal/Slots:
The SettingsWindow emits textEdit(QString) signal if Dialog Accepted, and MainWindow receives this signal via on_textEdit(QString) slot and writes it to its own text field:
SettingsWindow reading text input and emitting signal textEdit(QString):
MainWindow receiving signal via slot on_textEdit(QString):
And this is the code:
maindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_pushButton_clicked();
void on_textEdited(QString txt);
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "settingsdialog.h"
#include <memory>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
auto dlg = new SettingsDialog{this};
connect(dlg, &SettingsDialog::textEdit, this, &MainWindow::on_textEdited);
dlg->setAttribute(Qt::WA_DeleteOnClose);
dlg->show();
}
void MainWindow::on_textEdited(QString txt)
{
ui->textEdit->setText(txt);
}
settingsdialog.h
#ifndef SETTINGSDIALOG_H
#define SETTINGSDIALOG_H
#include <QDialog>
namespace Ui {
class SettingsDialog;
}
class SettingsDialog : public QDialog
{
Q_OBJECT
public:
explicit SettingsDialog(QWidget *parent = nullptr);
~SettingsDialog();
signals:
void textEdit(QString txt);
private slots:
void on_buttonBox_accepted();
private:
Ui::SettingsDialog *ui;
};
#endif // SETTINGSDIALOG_H
settingsdialog.cpp
#include "settingsdialog.h"
#include "ui_settingsdialog.h"
SettingsDialog::SettingsDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::SettingsDialog)
{
ui->setupUi(this);
}
SettingsDialog::~SettingsDialog()
{
delete ui;
}
void SettingsDialog::on_buttonBox_accepted()
{
emit textEdit(ui->textEdit->toPlainText());
}
More about Signal/Slots
I need to edit a QLabel from MainWindow's UI in another source file. I've tried messing around with singals and slots, but honestly I'm completely lost and the Qt documentation doesn't help me in this exact situation. I understand that this has been asked in the past, but I have not found a solution that works for me. I'm new to Qt, and C++ in general.
I have the following code (greatly simplified):
"mainwindow.h":
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow {
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
void setFoo(char* text);
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
"mainwindow.cpp"
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow) {
ui->setupUi(this);
this->statusBar()->setSizeGripEnabled(false);
}
MainWindow::~MainWindow() {
delete ui;
}
void MainWindow::setFoo(char* text) {
ui->fooLabel->setText(text);
}
"secondwindow.h"
#ifndef SECONDWINDOW_H
#define SECONDWINDOW_H
#include <QWidget>
namespace Ui {
class SecondWindow;
}
class SecondWindow: public QWidget {
Q_OBJECT
public:
explicit SecondWindow(QWidget *parent = 0);
~SecondWindow();
private:
Ui::SecondWindow*ui;
}
#endif // SecondWindow_H
"secondwindow.cpp"
#include "secondwinodw.h"
#include "ui_secondwinodw.h"
#include "mainwindow.h"
SecondWindow::SecondWindow(QWidget *parent) :
QWidget(parent),
ui(new Ui::SecondWindow) {
ui->setupUi(this);
}
SecondWindow::~SecondWindow() {
delete ui;
}
void SecondWindow::on_fooButton_clicked() {
MainWindow::setFoo("example");//The method is private so this is not possible, but this is my goal
}
When a user clicks on fooButton, I need to access and edit the MainWindow's UI QLabel(or a public method that does this).
The secondwindow is not being created in the main() function
void MainWindow::keyPressEvent(QKeyEvent *event) {
switch (event->key()) {
case Qt::Key_A:
if (event->modifiers()==Qt::ShiftModifier) {
SecondWindow*secwind= new SecondWindow();
secwind->show();
}
break;
}
}
In OOP the ones that interact are the objects, not the classes or the files, that is, the following expression:I need to edit QLabel from MainWindow's UI in another source file It does not make sense, what you should say is that an object of the MainWindow class is modified by another object of the SecondWindow class. The files do not make the program, the interaction between objects do it.
I'm assuming that both objects are created in the main.cpp:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w1;
SecondWindow w2;
w1.show();
w2.show();
return a.exec();
}
Now if I go to attack the main problem, Qt handles the concept of signals and slots, so we will use it, as the action to a SecondWindow object will cause the information to be sent, I will create a signal that carries that information:
secondwindow.h
#ifndef SECONDWINDOW_H
#define SECONDWINDOW_H
#include <QWidget>
namespace Ui {
class SecondWindow;
}
class SecondWindow: public QWidget {
Q_OBJECT
public:
explicit SecondWindow(QWidget *parent = 0);
~SecondWindow();
signals:
void messageChanged(const QString & message); // <---
private slots:
void void SecondWindow::on_fooButton_clicked();
private:
Ui::SecondWindow*ui;
}
#endif // SecondWindow_H
when the button is pressed, the signal with the information must be emitted
secondwindow.cpp
...
void SecondWindow::on_fooButton_clicked() {
emit messageChanged("example");//The method is private so this is not possible, but this is my goal
}
Now we go to the receiver's side, how will we get a slots, you have done it but do not use char *, that's C, we're using C++ and much better we're using Qt, it's best to use QString:
mainwindow.h
....
void setFoo(const QString & text);
mainwindow.cpp
...
void MainWindow::setFoo(const QString & text) {
ui->fooLabel->setText(text);
}
And finally we make the connections:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w1;
SecondWindow w2;
QObject::connect(&w2, &SecondWindow::messageChanged, &w1, &MainWindow::setFoo);
w1.show();
w2.show();
return a.exec();
}
update:
void MainWindow::keyPressEvent(QKeyEvent *event) {
switch (event->key()) {
case Qt::Key_A:
if (event->modifiers()==Qt::ShiftModifier) {
SecondWindow*secwind= new SecondWindow();
connect(secwind, &SecondWindow::messageChanged, this, &MainWindow::setFoo);
secwind->show();
}
break;
}
}
I would like to make some modifications of the main window from another file.
I created another ui file Form1Window (which open when a button is cliked in the MainWindow).
I want to call from the class Form1Window a function named test() of the MainWindow class
I succeed in calling function test() but I can't execute the whole content of the function (I can display a message but can't execute the part where I want to clear an edittext)
MainWindow.h
#include "form1window.h"
public slots:
void nettoyer();
private slots:
void openFrom1();
private:
Ui::MainWindow *ui;
From1Window *uiFrom1;
};
MainWindow.cpp
void MainWindow::openFrom1()
{
uiFrom1 = new From1Window(this);
uiFrom1->show();
}
void MainWindow::nettoyer(){
QMessageBox msgBox;
msgBox.setText("test");
msgBox.setIcon(QMessageBox::Information);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.exec();
ui->auteur->clear();
//THIS LINE HAS NO EFFECT WHEN CALLED FROM THE OTHER CLASS
}
form1window.cpp
#include "mainwindow.h"
#include "ui_form1window.h"
void From1Window::on_supprimer_clicked()
{
MainWindow *a=new MainWindow ();
a->test();
close();
}
I've read about the role of the pointer of MainWindow class (C++ /Qt Proper way to access ui from another class in qt //Edited) and I've also tried connect()
Thank for your help
//THIS LINE HAS NO EFFECT WHEN CALLED FROM THE OTHER CLASS
this->ui->auteur->clear();
The line will never executed unless you dismiss QMessageBox. This is because you triggered QMessageBox with exec() function. This function has its own event queue and does not return until finishes. You may set QMessageBox as modal and display it with show() method. In that case QMessageBox will not block execution of the the flow.
This problem can also happen with QDialog(s) if you display them with exec().
I provide you a simple two window signal/slot example:
main.cpp
#include "mainwindow.h"
#include "form.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Form f;
f.show();
return a.exec();
}
form.h
#ifndef FORM_H
#define FORM_H
#include <QWidget>
#include <QPushButton>
class Form : public QWidget
{
Q_OBJECT
public:
explicit Form(QWidget *parent = 0);
~Form();
private:
QPushButton *pb;
};
#endif // FORM_H
form.cpp
#include "form.h"
#include "mainwindow.h"
#include <QDebug>
Form::Form(QWidget *parent) : QWidget(parent)
{
MainWindow *mw = new MainWindow();
pb = new QPushButton("clickME", this);
QObject::connect(pb, SIGNAL(clicked()), mw, SLOT(test()));
mw->show();
}
Form::~Form()
{
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QLabel>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
void test();
private:
QLabel *l;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include <QDebug>
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
l = new QLabel("test", this);
}
MainWindow::~MainWindow()
{
}
void MainWindow::test() {
qDebug() << "test called!" << endl;
l->setText("text changed");
}
This works for me.
output
Hii I am new to programming i have stated learning about c++ and qt . i want to create a simple program in which user gives input from gui, these input are then send to a function (which is a separate header and cpp file) the value is evaluated in this function and again displayed in the gui.
i have three file namely main.cpp, (mainwindow.cpp & mainwindow.h), and (addition.cpp and addition.h)
i want that the values are read from mainwindow.ui (from lineedit) they are then send to the function addition.cpp and evaluated and is send back to mainwindow.cpp or mainwindow.ui (to lineedit) so that i can access this result.
here is the code i was trying
please help me in understanding the process
//main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
//mainwindow.h.
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include "addition.h"
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
QObject *sumnum;
private:
Ui::MainWindow *ui;
float number1,number2;
public slots:
void results(float);
private slots:
void on_addnum_clicked();
};
#endif // MAINWINDOW_H
//mainwindow.cpp.
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
sumnum = new QObject(this);
connect(sumnum,SIGNAL(add(float)),this,SLOT(results(float)));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::results(float answer)
{
ui->sum->setText(QString::number(answer));
}
void MainWindow::on_addnum_clicked()
{
addresult(ui->num1->text().toDouble(),ui->num2->text().toDouble());
}
//addition.h
#ifndef ADDITION_H
#define ADDITION_H
#include <QObject>
class addition : public QObject
{
Q_OBJECT
public:
explicit addition(QObject *parent = 0);
void run(float, float);
private:
float answer;
signals:
void add(float);
public slots:
};
#endif // ADDITION_H
//addition.cpp
#ifndef ADDITION_H
#define ADDITION_H
#include <QObject>
class addition : public QObject
{
Q_OBJECT
public:
explicit addition(QObject *parent = 0);
void run(float, float);
private:
float answer;
signals:
void add(float);
public slots:
};
#endif // ADDITION_H
In your MainWindow class, the type of sumnum variable has to be addition because you'll need the complete type in order to connect to its signals/slots
sumnum class should have a public function like void add(flaot n1, float n2) so you can call it in your on_addnum_clicked function
I would like share a string between two instances of QWidget.
In main.cpp, two objects are instantiated and shown like this:
#include "dialog.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Dialog w1,w2; //Derived from QWidget
w1.show();
w2.show();
return a.exec();
}
I would introduce SharedState class:
// shared_state.h
#ifndef SHARED_STATE_HPP
#define SHARED_STATE_HPP
#include <QObject>
class SharedState : public QObject
{
Q_OBJECT
public:
SharedState(QString initialValue = "")
: currentValue(initialValue)
{}
QString getCurrentValue()
{
return currentValue;
}
public slots:
void setValue(QString newValue)
{
if(currentValue != newValue)
{
currentValue = newValue;
emit valueChanged(currentValue);
}
}
signals:
void valueChanged(QString);
private:
QString currentValue;
};
#endif // SHARED_STATE_HPP
Now I would provide reference to SharedState in Dialog's constructor,
// dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include <QWidget>
#include "shared_state.h"
namespace Ui {
class Dialog;
}
class Dialog : public QWidget
{
Q_OBJECT
public:
explicit Dialog(SharedState& state, QWidget *parent = 0);
~Dialog();
private slots:
void handleTextEdited(const QString&);
public slots:
void handleInternalStateChanged(QString);
private:
Ui::Dialog *ui;
SharedState& state;
};
#endif // DIALOG_H
You may have noticed that I have added two slots, one to handle the case when the text is manually edited and one when shared state will inform us that we are out of date.
Now in Dialog's constructor I had to set initial value to textEdit, and connect signals to slots.
// dialog.cpp
#include "dialog.h"
#include "ui_dialog.h"
Dialog::Dialog(SharedState& state, QWidget *parent) :
QWidget(parent),
ui(new Ui::Dialog),
state(state)
{
ui->setupUi(this);
ui->textEdit->setText(state.getCurrentValue());
QObject::connect(ui->textEdit, SIGNAL(textEdited(QString)),
this, SLOT(handleTextEdited(QString)));
QObject::connect(&state, SIGNAL(valueChanged(QString)),
this, SLOT(handleInternalStateChanged(QString)));
}
Dialog::~Dialog()
{
delete ui;
}
void Dialog::handleTextEdited(const QString& newText)
{
state.setValue(newText);
}
void Dialog::handleInternalStateChanged(QString newState)
{
ui->textEdit->setText(newState);
}
Now the change in the main function:
// main.cpp
#include "dialog.h"
#include "shared_state.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
SharedState state("Initial Value");
Dialog w1(state), w2(state);
w1.show();
w2.show();
return a.exec();
}