Basic Signals and Slots - don't know where to go.
-
HI,
So, basic Signals and Slots here.
I just can't work out where to place the code in order to have it executed.Short of it is:
I have a MainWindow.
When you click on "Set Date" it opens a Qt Designer Form Class that contains a Calendar Widget.
If you hit "Okay" it executes an accept();
If you hit "Cancel" it executes close();I have found how to get these 3 values (day, month, year) back to the MainWindow.
I want these three values to then trigger a signal which is picked up by a slot to populate a few form fields on MainWindow, but then also be sent off other places.
If no date is selected, then a default date is set for those values in MainWindow instead.Just can't quite get my head around it.
Code below:
mainwindow.cpp:
#include "mainwindow.h" #include "./ui_mainwindow.h" #include "littledate.h" #include <QString> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); } MainWindow::~MainWindow() { delete ui; } void MainWindow::populateStuff(int thisDay, int thisMonth, int thisYear) { // Need thisDay, thisMonth and thisYear to receive values from a signal/slot // If none are received, need the following defaults: //int thisDay = 1; //int thisMonth = 5; //int thisYear = 2021; ui->Day->setText(QString::number(thisDay)); ui->Month->setText(QString::number(thisMonth)); ui->Year->setText(QString::number(thisYear)); // Do some other stuff with values stored in thisDay, thisMonth, thisYear } void MainWindow::on_quitButton_clicked() { close(); } void MainWindow::on_pushButton_clicked() { int day, month, year; littleDate dateSel; dateSel.setModal(true); if (dateSel.exec() == QDialog::Accepted) { day = dateSel.getDay(); month = dateSel.getMonth(); year = dateSel.getYear(); } // Need day, month, year to trigger a signal/slot that // sends values to populatestuff() }
littledate.cpp:
#include "littledate.h" #include "ui_littledate.h" littleDate::littleDate(QWidget *parent) : QDialog(parent), ui(new Ui::littleDate) { ui->setupUi(this); } littleDate::~littleDate() { delete ui; } void littleDate::setDay(int thisDay) { day = thisDay; } void littleDate::setMonth(int thisMonth) { month = thisMonth; } void littleDate::setYear(int thisYear) { year = thisYear; } int littleDate::getDay() const { return day; } int littleDate::getMonth() const { return month; } int littleDate::getYear() const { return year; } void littleDate::on_cancelButton_clicked() { close(); } void littleDate::on_okButton_clicked() { QDate date = ui->calendarWidget->selectedDate(); setDay(date.day()); setMonth(date.month()); setYear(date.year()); accept(); }
Any ideas?
Many thanks.
-
HI,
So, basic Signals and Slots here.
I just can't work out where to place the code in order to have it executed.Short of it is:
I have a MainWindow.
When you click on "Set Date" it opens a Qt Designer Form Class that contains a Calendar Widget.
If you hit "Okay" it executes an accept();
If you hit "Cancel" it executes close();I have found how to get these 3 values (day, month, year) back to the MainWindow.
I want these three values to then trigger a signal which is picked up by a slot to populate a few form fields on MainWindow, but then also be sent off other places.
If no date is selected, then a default date is set for those values in MainWindow instead.Just can't quite get my head around it.
Code below:
mainwindow.cpp:
#include "mainwindow.h" #include "./ui_mainwindow.h" #include "littledate.h" #include <QString> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); } MainWindow::~MainWindow() { delete ui; } void MainWindow::populateStuff(int thisDay, int thisMonth, int thisYear) { // Need thisDay, thisMonth and thisYear to receive values from a signal/slot // If none are received, need the following defaults: //int thisDay = 1; //int thisMonth = 5; //int thisYear = 2021; ui->Day->setText(QString::number(thisDay)); ui->Month->setText(QString::number(thisMonth)); ui->Year->setText(QString::number(thisYear)); // Do some other stuff with values stored in thisDay, thisMonth, thisYear } void MainWindow::on_quitButton_clicked() { close(); } void MainWindow::on_pushButton_clicked() { int day, month, year; littleDate dateSel; dateSel.setModal(true); if (dateSel.exec() == QDialog::Accepted) { day = dateSel.getDay(); month = dateSel.getMonth(); year = dateSel.getYear(); } // Need day, month, year to trigger a signal/slot that // sends values to populatestuff() }
littledate.cpp:
#include "littledate.h" #include "ui_littledate.h" littleDate::littleDate(QWidget *parent) : QDialog(parent), ui(new Ui::littleDate) { ui->setupUi(this); } littleDate::~littleDate() { delete ui; } void littleDate::setDay(int thisDay) { day = thisDay; } void littleDate::setMonth(int thisMonth) { month = thisMonth; } void littleDate::setYear(int thisYear) { year = thisYear; } int littleDate::getDay() const { return day; } int littleDate::getMonth() const { return month; } int littleDate::getYear() const { return year; } void littleDate::on_cancelButton_clicked() { close(); } void littleDate::on_okButton_clicked() { QDate date = ui->calendarWidget->selectedDate(); setDay(date.day()); setMonth(date.month()); setYear(date.year()); accept(); }
Any ideas?
Many thanks.
@Uberlinc said in Basic Signals and Slots - don't know where to go.:
// Need day, month, year to trigger a signal/slot that // sends values to populatestuff()
No you don't need any such here --- simply call the
MainWindow::populateStuff()
method with the parameters from here directly:populateStuff(day, month, year);
That's it! No need for signals/slots for this action.
but then also be sent off other places.
If you really need that for other purposes, and if for whatever reason it needs to be done by a signal rather than just having
MainWindow
call method(s) elsewhere, you will want to create your own signal for this. Which fortunatey is very easy:// in mainwindow.h, in the `MainWindow` class declaration signals: void dateChanged(int day, int month, int year); // or maybe change to using a `QDate` type // in e.g. other modules' `.h` files public slots: void onDateChanged(int day, int month, int year); // and implementation of slot method in `.cpp` file as usual // in mainwindow.cpp, at suitable place(s) where you have created the other module(s)' instance connect(this, &MainWindow::dateChanged, otherObject, &OtherClass::onDateChanged); // in mainwindow.cpp, at suitable place(s) such as in `on_pushButton_clicked()` emit dateChanged(day, month, year);
-
That's a great help!
Thank you!I wish to go ahead with the Signals & Slots part as I had intended this app to be an exercise to get my head around Signals and Slots. (As you can see, I'm still struggling a little bit.)
I'll try to implement your changes and be back if I get stuck.
Many thanks!
-
Okay, so I've played around with it but, much to my dismay, I'm just not getting it.
I do apologise for asking you to hold my hand, but can someone show me exactly were on my code I need to stick the signals, slots, emitters and collectors?I know it's rude to dump a whole lot of code on someone, but this is the simplest example I can come up with.
(I'm self-taught, part-time in between being a working Dad, so I'm struggling! I do apologise!)The aim is to have the date set as a default which can then be used to do other things, unless an event is driven by the change of date.
Any help is greatly appreciated!
littledate.h:
#ifndef LITTLEDATE_H #define LITTLEDATE_H #include <QDialog> namespace Ui { class littleDate; } class littleDate : public QDialog { Q_OBJECT public: explicit littleDate(QWidget *parent = nullptr); // Constructor ~littleDate(); // Destructor void setDay(int); // Mutator function for day value void setMonth(int); // Mutator function for month value void setYear(int); // Mutator function for year value int getDay() const; // Accessor function for day value int getMonth() const; // Mutator function for month value int getYear() const; // Mutator function for year value public slots: void onDateChanged(int day, int month, int year); private slots: void on_cancelButton_clicked(); void on_okButton_clicked(); private: Ui::littleDate *ui; int day; int month; int year; }; #endif // LITTLEDATE_H
littledate.cpp:
#include "littledate.h" #include "ui_littledate.h" littleDate::littleDate(QWidget *parent) : QDialog(parent), ui(new Ui::littleDate) { ui->setupUi(this); } littleDate::~littleDate() { delete ui; } void littleDate::setDay(int thisDay) { day = thisDay; } void littleDate::setMonth(int thisMonth) { month = thisMonth; } void littleDate::setYear(int thisYear) { year = thisYear; } int littleDate::getDay() const { return day; } int littleDate::getMonth() const { return month; } int littleDate::getYear() const { return year; } void littleDate::on_cancelButton_clicked() { close(); } void littleDate::on_okButton_clicked() { QDate date = ui->calendarWidget->selectedDate(); setDay(date.day()); setMonth(date.month()); setYear(date.year()); accept(); }
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 populateStuff(); signals: void dateChanged(int day, int month, int year); private slots: void on_quitButton_clicked(); void on_pushButton_clicked(); private: Ui::MainWindow *ui; }; #endif // MAINWINDOW_H
mainwindow.cpp:
#include "mainwindow.h" #include "./ui_mainwindow.h" #include "littledate.h" #include <QString> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); } MainWindow::~MainWindow() { delete ui; } void MainWindow::populateStuff() { // Set values for date. // Starts with defaults, unless an action is detected, and then uses that value instead int thisDay = 1; // default day value if not changed by user int thisMonth = 5; // default month value if not changed by user int thisYear = 2021; // default year value if not changed by user // Somewhere in here, it looks to see if the date values have been changed by the user. ui->Day->setText(QString::number(thisDay)); ui->Month->setText(QString::number(thisMonth)); ui->Year->setText(QString::number(thisYear)); // Do some other stuff with values stored in thisDay, thisMonth, thisYear // i.e. passed off to another function. } void MainWindow::on_quitButton_clicked() { close(); } void MainWindow::on_pushButton_clicked() { int day, month, year; littleDate dateSel; dateSel.setModal(true); connect(this, &MainWindow::dateChanged, dateSel, &littleDate::onDateChanged); if (dateSel.exec() == QDialog::Accepted) { day = dateSel.getDay(); month = dateSel.getMonth(); year = dateSel.getYear(); } emit dateChanged(day, month, year); }
-
Okay, so I've played around with it but, much to my dismay, I'm just not getting it.
I do apologise for asking you to hold my hand, but can someone show me exactly were on my code I need to stick the signals, slots, emitters and collectors?I know it's rude to dump a whole lot of code on someone, but this is the simplest example I can come up with.
(I'm self-taught, part-time in between being a working Dad, so I'm struggling! I do apologise!)The aim is to have the date set as a default which can then be used to do other things, unless an event is driven by the change of date.
Any help is greatly appreciated!
littledate.h:
#ifndef LITTLEDATE_H #define LITTLEDATE_H #include <QDialog> namespace Ui { class littleDate; } class littleDate : public QDialog { Q_OBJECT public: explicit littleDate(QWidget *parent = nullptr); // Constructor ~littleDate(); // Destructor void setDay(int); // Mutator function for day value void setMonth(int); // Mutator function for month value void setYear(int); // Mutator function for year value int getDay() const; // Accessor function for day value int getMonth() const; // Mutator function for month value int getYear() const; // Mutator function for year value public slots: void onDateChanged(int day, int month, int year); private slots: void on_cancelButton_clicked(); void on_okButton_clicked(); private: Ui::littleDate *ui; int day; int month; int year; }; #endif // LITTLEDATE_H
littledate.cpp:
#include "littledate.h" #include "ui_littledate.h" littleDate::littleDate(QWidget *parent) : QDialog(parent), ui(new Ui::littleDate) { ui->setupUi(this); } littleDate::~littleDate() { delete ui; } void littleDate::setDay(int thisDay) { day = thisDay; } void littleDate::setMonth(int thisMonth) { month = thisMonth; } void littleDate::setYear(int thisYear) { year = thisYear; } int littleDate::getDay() const { return day; } int littleDate::getMonth() const { return month; } int littleDate::getYear() const { return year; } void littleDate::on_cancelButton_clicked() { close(); } void littleDate::on_okButton_clicked() { QDate date = ui->calendarWidget->selectedDate(); setDay(date.day()); setMonth(date.month()); setYear(date.year()); accept(); }
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 populateStuff(); signals: void dateChanged(int day, int month, int year); private slots: void on_quitButton_clicked(); void on_pushButton_clicked(); private: Ui::MainWindow *ui; }; #endif // MAINWINDOW_H
mainwindow.cpp:
#include "mainwindow.h" #include "./ui_mainwindow.h" #include "littledate.h" #include <QString> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); } MainWindow::~MainWindow() { delete ui; } void MainWindow::populateStuff() { // Set values for date. // Starts with defaults, unless an action is detected, and then uses that value instead int thisDay = 1; // default day value if not changed by user int thisMonth = 5; // default month value if not changed by user int thisYear = 2021; // default year value if not changed by user // Somewhere in here, it looks to see if the date values have been changed by the user. ui->Day->setText(QString::number(thisDay)); ui->Month->setText(QString::number(thisMonth)); ui->Year->setText(QString::number(thisYear)); // Do some other stuff with values stored in thisDay, thisMonth, thisYear // i.e. passed off to another function. } void MainWindow::on_quitButton_clicked() { close(); } void MainWindow::on_pushButton_clicked() { int day, month, year; littleDate dateSel; dateSel.setModal(true); connect(this, &MainWindow::dateChanged, dateSel, &littleDate::onDateChanged); if (dateSel.exec() == QDialog::Accepted) { day = dateSel.getDay(); month = dateSel.getMonth(); year = dateSel.getYear(); } emit dateChanged(day, month, year); }
@Uberlinc said in Basic Signals and Slots - don't know where to go.:
connect(this, &MainWindow::dateChanged, dateSel, &littleDate::onDateChanged);
This is wrong. Remove it and so far everything works, the main window gets the new date value from the dialog after the
exec()
, right?If all you want to do is then update some widgets on
MainWindow
you can do so directly from there without any signals/slots, immediately after theexec()
returns.Only if as you said originally:
but then also be sent off other places.
do you need signals/slots. In that case you have your
emit dateChanged(day, month, year);
to raise the signal (move it into theif (dateSel.exec() == QDialog::Accepted)
block). You do not want anypublic slots: void onDateChanged(int day, int month, int year);
in
littleDate
class. You only want it in whatever other classes/widgets/windows you have created which you want to be notified that the data has changed. Like:// otherwindow.h class OtherWindow : public QWidget { public slots: void onDateChanged(int day, int month, int year); } // otherwindow.cpp void OtherWindow::onDateChanged(int day, int month, int year) { // do whatever in `OtherWindow` } // mainwindow.cpp // wherever you create an `OtherWindow` instance otherWindow = OtherWindow; connect(this, &MainWindow::dateChanged, otherWindow, &OtherWindow::onDateChanged); otherWindow.show();
If you really wanted to use a slot in
MainWindow
to be notified of date changed --- which you should not need because you know that immediately afterdateSel.exec()
inMainWindow::on_pushButton_clicked()
and can call whatever inMainWindow
directly from there --- then you would define aMainWindow::onDateChanged
slot andconnect(this, &MainWindow::dateChanged, this, &MainWindow::onDateChanged);
-
Thanks.
I'm still not understanding how the "populatestuff()" function is to be used, then.
At what point is it called to populate fields in the mainwindow form with defaults, whether or not the CalendarWidget is used (in the second window) to select a new date?It should populate the date from the beginning with a default date.
Then, and only then, if the user clicks on the second window and selects a date, the date values change and the fields in mainwindow are updated.Not sure how to achieve this.
Thanks.
-
Thanks.
I'm still not understanding how the "populatestuff()" function is to be used, then.
At what point is it called to populate fields in the mainwindow form with defaults, whether or not the CalendarWidget is used (in the second window) to select a new date?It should populate the date from the beginning with a default date.
Then, and only then, if the user clicks on the second window and selects a date, the date values change and the fields in mainwindow are updated.Not sure how to achieve this.
Thanks.
@Uberlinc said in Basic Signals and Slots - don't know where to go.:
It should populate the date from the beginning with a default date.
So call it from
MainWindow::MainWindow()
constructor. Move the setting ofthisDay
/thisMonth
/thisYear
out of the body ofpopulateStuff()
and either pass their desired values in as parameters or make those variables class member variables.Then, and only then, if the user clicks on the second window and selects a date, the date values change and the fields in mainwindow are updated.
So call it from
MainWindow::on_pushButton_clicked()
, inif (dateSel.exec() == QDialog::Accepted)
. Either pass the new values as parameters or store them as class member variables, as per whatever you did for constructor call. Or do whatever work there, and you don't need to callpopulateStuff()
.In both
populateStuff()
&on_pushButton_clicked()
you need to think about whetherday
/month
/year
should be local variables or member variables, e.g. at present they do nothing inon_pushButton_clicked()
other than get passed to theemit
. -
Okay, that worked.
I was actually hoping that it might be a good exercise to get my head around Signals and Slots.
I guess not.Any recommendations on tutorials or exercises to help me get a good grasp of Signals and Slots?
Thanks,
@Uberlinc
I wrote earlier:If you really wanted to use a slot in MainWindow to be notified of date changed --- which you should not need because you know that immediately after dateSel.exec() in MainWindow::on_pushButton_clicked() and can call whatever in MainWindow directly from there --- then you would define a MainWindow::onDateChanged slot and
connect(this, &MainWindow::dateChanged, this, &MainWindow::onDateChanged);
So do that and just
emit
the signal fromon_pushButton_clicked()
. Do not change whatever stuff directly fromon_pushButton_clicked()
(e.g. by callingpopulateStuff()
) after all, do it in aMainWindow::onDateChanged()
slot (or makeMainWindow::populateStuff()
a slot which you connect to the signal) instead.