QStackedWidget: How to check if the next widget should be shown
-
I've made an application with a stacked widget. In the MainWindow the widgets are set. The first widget is a login page, after a succesfull login I'd like to show the second page. How can I check inside the MainWindow if the login was succesfull? (Both widgets are classes with ui's) I also promoted the widgets of the stackedWidget to these classes.
this is my code:
MainWindow.cpp
#include "mainwindow.h" #include "loginwidget.h" #include "ui_mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); ui->stackedWidget->setCurrentIndex(0); } MainWindow::~MainWindow() { delete ui; }
loginWidget.cpp
#include "loginwidget.h" #include "ui_loginwidget.h" LoginWidget::LoginWidget(QWidget *parent) : QWidget(parent), ui(new Ui::LoginWidget) { ui->setupUi(this); } LoginWidget::~LoginWidget() { delete ui; } bool LoginWidget::loginSuccesfull() { QString username = ui->lineEdit_2->text(); QString password = ui->lineEdit->text(); if(username == "Test" && password == "Test123") { return true; } else { return false; } }
AfterLoginScreen (currently a non-functional widget)
#include "afterloginscreen.h" #include "ui_afterloginscreen.h" AfterLoginScreen::AfterLoginScreen(QWidget *parent) : QWidget(parent), ui(new Ui::AfterLoginScreen) { ui->setupUi(this); } AfterLoginScreen::~AfterLoginScreen() { delete ui; }
-
@hobbyProgrammer said in QStackedWidget: How to check if the next widget should be shown:
but I don't think so
Then it can't work.
Use new Qt5 connect syntax to be sure signal/slot are really connected:connect(login, &LoginWidget::loginSuccesfull, this, &MainWindow::showApp);
-
@hobbyProgrammer said in QStackedWidget: How to check if the next widget should be shown:
How can I check inside the MainWindow if the login was succesfull? (
Call your
LoginWidget::loginSuccesfull()
!If you mean, how do you get a reference to the login widget to call
loginWidget->loginSuccesfull()
, either keep a reference to theloginWidget
at the time you create it/put it into theQStackedWidget
, or use something likeloginWidget = qobject_cast<LoginWidget*>(ui->stackedWidget.widget(1))
-
@JonB Oh I'm sorry, it should happen on a pushbutton (when it's pressed, it checks if the login was good)
So like this:
bool LoginWidget::loginSuccesfull() { QString username = ui->lineEdit_2->text(); QString password = ui->lineEdit->text(); if(username == "Test" && password == "Test123") { return true; } else { return false; } } void LoginWidget::on_pushButton_clicked() { loginSuccesfull(); }
but how do I check the value of loginSuccesfull() in the mainwindow?
-
@hobbyProgrammer
There is no point invoking a function fromon_pushButton_clicked()
which just returnstrue
orfalse
without acting on the return result.There are many ways to achieve what you want. I'll just say that it would be easier if you chose to make the login page a modal dialog instead of one of the stacked widgets. That's a different interface, I don't know how you feel about that.
If you want to keep the login in stacked widget as now: Probably, stop
loginSuccessfull()
from being a function returning a boolean. Instead, in thefalse
case have it show the user an error message. In thetrue
case, one of:- Have it switch back to some other window by calling
QStackedWidget::setCurrentIndex(0)
(it will have to have access toui->stackedWidget
). - Have it raise a signal to indicate successful logon, and the main window will have a slot for that so that the
ui->stackedWidget->setCurrentIndex(0)
can be done in the main window.
Ah, I see at present there is only one stacked widget, the login one, so the first alternative may not make sense. If you want your main window code to know about the login result, use the signal/slot mechanism.
- Have it switch back to some other window by calling
-
@hobbyProgrammer
No, for your case I would suggestLoginWidget::loginSuccesfull()
on success should raise a signal, andMainWindow
should place a slot on that signal to receive it.I'm sorry but I don't have time to write this all out for you, maybe someone else will. Have you read https://doc.qt.io/qt-5/signalsandslots.html, which is the core of how Qt uses signals & slots?
-
@JonB so should it be something like this?
connect(ui->stackedWidget->indexOf(0), SIGNAL(loginSuccesfull()), this, SLOT(showApp()));
I might be close, but it's not working yet. Do you see what I am doing wrong?
I also tried this:
Login *login = ui->stackedWidget->indexOf(0); connect(login, SIGNAL(loginSuccesfull()), this, SLOT(showApp()));
-
@hobbyProgrammer
Whatever else might be wrong,QStackedWidget::indexOf()
is totally the wrong way round. As I wrote earlier, you will need to useQStackedWidget::widget()
, and if you need a reference to it being aLoginWidget
to access members of that class you will want something like:loginWidget = qobject_cast<LoginWidget*>(ui->stackedWidget.widget(0))
-
@JonB thank you.
LoginWidget *login = qobject_cast<LoginWidget*>(ui->stackedWidget->widget(0)); connect(login, SIGNAL(loginSuccesfull()), this, SLOT(showApp()));
I currently get these errors (as loginSuccesfull is a public bool method):
QObject::connect: No such signal LoginWidget::loginSuccesfull() in ..\stackedLogin\mainwindow.cpp:14 QObject::connect: (sender name: 'page') QObject::connect: (receiver name: 'MainWindow')
whenever I change loginSuccesfull() to a signal instead of public bool I get these errors:
LNK2005:"public: bool _thiscall LoginWidget::loginSuccesfull(void)......" and LNK1169: one or more multiply defined symbols found
-
A Signal must not have a definition, only a declaration.
The definition is made automatically in generated code by moc
-
@hobbyProgrammer
In some shape or form you have not changed over the code to how signals/slots are declared and work in Qt. There are lots of example to read. You will need correct Qt declarations usingsignals
&slots
in your header files, andloginSuccesfull()
won't be somebool
function, it willemit
the signal.I will leave others to help you with this, I don't even do Qt in C++.
-
the idea would be, that you emit the signal, as soon as your function verifies, that the login was successful !
void LoginWidget::on_pushButton_clicked() { QString username = ui->lineEdit_2->text(); QString password = ui->lineEdit->text(); if(username == "Test" && password == "Test123") { emit loginSuccessful(); } }
-
@hobbyProgrammer
Subject to @J-Hilk suggesting an alternative, as I wrote earlier retain yourloginSuccesfull()
as the slot for the pushbutton click. Have itemit
a signal you define on successful validation of the widgets, the signal is a separate thing from your function which you must define as per the Qt/C++ rules.EDIT OK, @J-Hilk's code is the same thing, it's just that he has defined the pushbutton slot as
on_pushButton_clicked()
and the signal aslogInSuccessful
, so there is no longer any (non-signal) function namedloginSuccesfull()
. -
@JonB alright, so using that code and these lines:
LoginWidget *login = qobject_cast<LoginWidget*>(ui->stackedWidget->widget(0)); connect(login, SIGNAL(loginSuccesfull()), this, SLOT(showApp()));
should result in showApp to happen anytime the login was succesfull?
-
@hobbyProgrammer
I'm hoping so! Did you try it? -
@JonB yes and it didn't work. I tried debugging but I can't seem to find what's going wrong. It hits the code where the emit loginSuccessfull() is set, but it doesn't go to the SLOT where it's connected to and it ends in :
while (!d->exit.loadAcquire()) processEvents(flags | WaitForMoreEvents | EventLoopExec);
-
@hobbyProgrammer Did you make sure
connect(login, SIGNAL(loginSuccesfull()), this, SLOT(showApp()));
succeeded? And is this "login" the one you're actually showing?