Easy switching between Widgets with PushButtons
-
wrote on 3 May 2017, 05:57 last edited by
Hello,
I just started Qt and have some trouble with switching widgets.
I want to switch widgets by clicking on a pushbutton. An Example would be having a menu first, go to the settings screen and then back to the menu.I do not want to create a new instance of a widget everytime I press on a button. Better define every reachable widget in the headers.
At the moment the programm crashed everytime I press on a button to get to the next page.
Here is my code:main.cpp
#include "widget.h" //#include "widget2.h" #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w; w.show(); return a.exec(); }
widget.h
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> class widget2; namespace Ui { class Widget; } class Widget : public QWidget { Q_OBJECT public: explicit Widget(QWidget *parent = 0); ~Widget(); widget2 * a; private slots: void on_pusha_clicked(); void on_exit_clicked(); private: Ui::Widget *ui; }; #endif // WIDGET_H
widget2.h
#ifndef WIDGET2_H #define WIDGET2_H #include <QWidget> class Widget; namespace Ui { class widget2; } class widget2 : public QWidget { Q_OBJECT public: explicit widget2(QWidget *parent = 0); ~widget2(); Widget* b; //welcome *firstPageWidget = new welcome; does not work private slots: void on_pushb_clicked(); void on_exit_clicked(); private: Ui::widget2 *ui; }; #endif // WIDGET2_H
widget.cpp
#include "widget.h" #include "ui_widget.h" #include "widget2.h" #include <iostream> Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); } Widget::~Widget() { std::cout << "widget 1 destroyed" <<std::endl; delete ui; } void Widget::on_pusha_clicked() { this->close(); // close this widget //widget2 a; <-- this works but creats a new instance every time... a->show(); // and show other one } void Widget::on_exit_clicked() { this->close(); }
widget2.cpp
#include "widget2.h" #include "ui_widget2.h" #include "widget.h" #include <iostream> widget2::widget2(QWidget *parent) : QWidget(parent), ui(new Ui::widget2) { std::cout << "widget 2 created"<< std::endl; ui->setupUi(this); } widget2::~widget2() { delete ui; std::cout << "widget 2 destroyed"<< std::endl; } void widget2::on_pushb_clicked() { this->close(); b->show(); } void widget2::on_exit_clicked() { this->close(); }
I hope anyone can help me.
Thanks in advance
Lunarix -
Hello,
I just started Qt and have some trouble with switching widgets.
I want to switch widgets by clicking on a pushbutton. An Example would be having a menu first, go to the settings screen and then back to the menu.I do not want to create a new instance of a widget everytime I press on a button. Better define every reachable widget in the headers.
At the moment the programm crashed everytime I press on a button to get to the next page.
Here is my code:main.cpp
#include "widget.h" //#include "widget2.h" #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w; w.show(); return a.exec(); }
widget.h
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> class widget2; namespace Ui { class Widget; } class Widget : public QWidget { Q_OBJECT public: explicit Widget(QWidget *parent = 0); ~Widget(); widget2 * a; private slots: void on_pusha_clicked(); void on_exit_clicked(); private: Ui::Widget *ui; }; #endif // WIDGET_H
widget2.h
#ifndef WIDGET2_H #define WIDGET2_H #include <QWidget> class Widget; namespace Ui { class widget2; } class widget2 : public QWidget { Q_OBJECT public: explicit widget2(QWidget *parent = 0); ~widget2(); Widget* b; //welcome *firstPageWidget = new welcome; does not work private slots: void on_pushb_clicked(); void on_exit_clicked(); private: Ui::widget2 *ui; }; #endif // WIDGET2_H
widget.cpp
#include "widget.h" #include "ui_widget.h" #include "widget2.h" #include <iostream> Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); } Widget::~Widget() { std::cout << "widget 1 destroyed" <<std::endl; delete ui; } void Widget::on_pusha_clicked() { this->close(); // close this widget //widget2 a; <-- this works but creats a new instance every time... a->show(); // and show other one } void Widget::on_exit_clicked() { this->close(); }
widget2.cpp
#include "widget2.h" #include "ui_widget2.h" #include "widget.h" #include <iostream> widget2::widget2(QWidget *parent) : QWidget(parent), ui(new Ui::widget2) { std::cout << "widget 2 created"<< std::endl; ui->setupUi(this); } widget2::~widget2() { delete ui; std::cout << "widget 2 destroyed"<< std::endl; } void widget2::on_pushb_clicked() { this->close(); b->show(); } void widget2::on_exit_clicked() { this->close(); }
I hope anyone can help me.
Thanks in advance
Lunarix -
wrote on 3 May 2017, 06:09 last edited by
You can use QStackedWidget and switch widgets with:
void setCurrentIndex(int index)
void setCurrentWidget(QWidget * widget)Also you can populate, add more, remove QStackedWidget widget's in QtDesigner.
-
Hello,
I just started Qt and have some trouble with switching widgets.
I want to switch widgets by clicking on a pushbutton. An Example would be having a menu first, go to the settings screen and then back to the menu.I do not want to create a new instance of a widget everytime I press on a button. Better define every reachable widget in the headers.
At the moment the programm crashed everytime I press on a button to get to the next page.
Here is my code:main.cpp
#include "widget.h" //#include "widget2.h" #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w; w.show(); return a.exec(); }
widget.h
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> class widget2; namespace Ui { class Widget; } class Widget : public QWidget { Q_OBJECT public: explicit Widget(QWidget *parent = 0); ~Widget(); widget2 * a; private slots: void on_pusha_clicked(); void on_exit_clicked(); private: Ui::Widget *ui; }; #endif // WIDGET_H
widget2.h
#ifndef WIDGET2_H #define WIDGET2_H #include <QWidget> class Widget; namespace Ui { class widget2; } class widget2 : public QWidget { Q_OBJECT public: explicit widget2(QWidget *parent = 0); ~widget2(); Widget* b; //welcome *firstPageWidget = new welcome; does not work private slots: void on_pushb_clicked(); void on_exit_clicked(); private: Ui::widget2 *ui; }; #endif // WIDGET2_H
widget.cpp
#include "widget.h" #include "ui_widget.h" #include "widget2.h" #include <iostream> Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); } Widget::~Widget() { std::cout << "widget 1 destroyed" <<std::endl; delete ui; } void Widget::on_pusha_clicked() { this->close(); // close this widget //widget2 a; <-- this works but creats a new instance every time... a->show(); // and show other one } void Widget::on_exit_clicked() { this->close(); }
widget2.cpp
#include "widget2.h" #include "ui_widget2.h" #include "widget.h" #include <iostream> widget2::widget2(QWidget *parent) : QWidget(parent), ui(new Ui::widget2) { std::cout << "widget 2 created"<< std::endl; ui->setupUi(this); } widget2::~widget2() { delete ui; std::cout << "widget 2 destroyed"<< std::endl; } void widget2::on_pushb_clicked() { this->close(); b->show(); } void widget2::on_exit_clicked() { this->close(); }
I hope anyone can help me.
Thanks in advance
Lunarix@Lunarix said in Easy switching between Widgets with PushButtons:
void widget2::on_pushb_clicked()
{
this->close();
b->show();
}well, you did not assign a pointer to a Widget instance to b - you're dereferencing a dangling pointer.
Should be:void widget2::on_pushb_clicked() { this->close(); b = new Widget(); b->show(); }
-
wrote on 3 May 2017, 06:13 last edited by
@Taz742
Hello, thanks for the reply.
Do you mean:void Widget::on_pusha_clicked() { this->close(); widget2* a = new widget2(); a->show(); }
But then I'd create a new instance everytime this function is called.
@Eligijus
Hello,
I looked for this, but the "go back to menu" button should not be always at the same position.
I tried it. But how should the child widget tell the stackedwidget that he should change setCurrentIndex? I was not able to do it. Can post my code if that helps.
Thank you for your help -
@Taz742
Hello, thanks for the reply.
Do you mean:void Widget::on_pusha_clicked() { this->close(); widget2* a = new widget2(); a->show(); }
But then I'd create a new instance everytime this function is called.
@Eligijus
Hello,
I looked for this, but the "go back to menu" button should not be always at the same position.
I tried it. But how should the child widget tell the stackedwidget that he should change setCurrentIndex? I was not able to do it. Can post my code if that helps.
Thank you for your help -
@Taz742
Im not sure if I set any parent dependencies.
Widget is the menu called by the main.widget2 is the "settings" screen, which can return to the menu Widget.
wrote on 3 May 2017, 06:32 last edited by@Lunarix
Try This:form.h #ifndef FORM_H #define FORM_H #include <QWidget> #include "mainwindow.h" class MainWindow; namespace Ui { class Form; } class Form : public QWidget { Q_OBJECT public: explicit Form(QWidget *parent = 0); ~Form(); MainWindow *wind; private slots: void on_pushButton_clicked(); private: Ui::Form *ui; }; #endif // FORM_H form.cpp #include "form.h" #include "ui_form.h" Form::Form(QWidget *parent) : QWidget(parent), ui(new Ui::Form) { ui->setupUi(this); wind = new MainWindow(); } Form::~Form() { delete ui; } void Form::on_pushButton_clicked() { delete this; wind->show(); } mainwindow.h #ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include "form.h" class Form; namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); Form *wid; private slots: void on_pushButton_clicked(); private: Ui::MainWindow *ui; }; #endif // MAINWINDOW_H mainwindow.cpp #include "mainwindow.h" #include "ui_mainwindow.h" #include "form.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); } MainWindow::~MainWindow() { delete ui; } void MainWindow::on_pushButton_clicked() { this->hide(); wid = new Form(); wid->show(); }
-
wrote on 3 May 2017, 06:40 last edited by
@Taz742
Thanks for the help. This looks good - but if I add some output in the constructor i see that there are instances created every time i click on a button.I just do not want to have 10000 hidden widgets - or will they get deleted and free memory?
-
@Taz742
Thanks for the help. This looks good - but if I add some output in the constructor i see that there are instances created every time i click on a button.I just do not want to have 10000 hidden widgets - or will they get deleted and free memory?
-
wrote on 3 May 2017, 06:56 last edited by
I use your code and just added the cout line so I see everytime a new instance is created.
Form::Form(QWidget *parent) : QWidget(parent), ui(new Ui::Form) { ui->setupUi(this); wind = new MainWindow(); std::cout << "Form created"<< std::endl; }
and it happens everytime i press on a button. So aren't there 10 hidden widgets open after 10 clicks?
-
I use your code and just added the cout line so I see everytime a new instance is created.
Form::Form(QWidget *parent) : QWidget(parent), ui(new Ui::Form) { ui->setupUi(this); wind = new MainWindow(); std::cout << "Form created"<< std::endl; }
and it happens everytime i press on a button. So aren't there 10 hidden widgets open after 10 clicks?
@Lunarix Then don't create the instance in on_pusha_clicked(). You can create the instance once for example in the constructor:
Widget::Widget() { ... widget2* a = new widget2(); ... }
-
wrote on 3 May 2017, 07:30 last edited by
@jsulm
Hello, but somehow then the code does not work at all.mainwindow.cpp
#include "mainwindow.h" #include "ui_mainwindow.h" #include "form.h" #include <iostream> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); std::cout << "Main created"<< std::endl; // wid = new Form(); either here } MainWindow::~MainWindow() { delete ui; } void MainWindow::on_pushButton_clicked() { this->hide(); wid = new Form(); // or here wid->show(); }
But if I use the first, then nothing happens on starting the programm.
If i usewidget2* a = new widget2();
in both constructor then the terminal prints that the MainWindow is created forever (so a loop there).
-
@jsulm
Hello, but somehow then the code does not work at all.mainwindow.cpp
#include "mainwindow.h" #include "ui_mainwindow.h" #include "form.h" #include <iostream> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); std::cout << "Main created"<< std::endl; // wid = new Form(); either here } MainWindow::~MainWindow() { delete ui; } void MainWindow::on_pushButton_clicked() { this->hide(); wid = new Form(); // or here wid->show(); }
But if I use the first, then nothing happens on starting the programm.
If i usewidget2* a = new widget2();
in both constructor then the terminal prints that the MainWindow is created forever (so a loop there).
@Lunarix Sorry I have no idea what you are doing!
"in both constructor" - what constructors do you mean and why in both?!
How is it possible that MainWindow is created in a loop? How and where do you create it?
Creating and showing a widget is actually a simple task. -
@Taz742
Hello, thanks for the reply.
Do you mean:void Widget::on_pusha_clicked() { this->close(); widget2* a = new widget2(); a->show(); }
But then I'd create a new instance everytime this function is called.
@Eligijus
Hello,
I looked for this, but the "go back to menu" button should not be always at the same position.
I tried it. But how should the child widget tell the stackedwidget that he should change setCurrentIndex? I was not able to do it. Can post my code if that helps.
Thank you for your helpwrote on 3 May 2017, 08:03 last edited by@Lunarix said in Easy switching between Widgets with PushButtons:
@Taz742
Hello, thanks for the reply.
Do you mean:void Widget::on_pusha_clicked() { this->close(); widget2* a = new widget2(); a->show(); }
But then I'd create a new instance everytime this function is called.
@Eligijus
Hello,
I looked for this, but the "go back to menu" button should not be always at the same position.
I tried it. But how should the child widget tell the stackedwidget that he should change setCurrentIndex? I was not able to do it. Can post my code if that helps.
Thank you for your helpYou have to ask yourself if you really need to use different classes for pages. If not then moving through pages is quite straight forward
connect(ui->pushButton, &QPushButton::released, [this]{ ui->stackedWidget->setCurrentIndex(1); });
if you need to use different classes for pages then you would need to access parent widget
qobject_cast<QStackedWidget *>(parentWidget())->setCurrentIndex(1);
or make connections from class object where you create page objects.
-
@Lunarix said in Easy switching between Widgets with PushButtons:
@Taz742
Hello, thanks for the reply.
Do you mean:void Widget::on_pusha_clicked() { this->close(); widget2* a = new widget2(); a->show(); }
But then I'd create a new instance everytime this function is called.
@Eligijus
Hello,
I looked for this, but the "go back to menu" button should not be always at the same position.
I tried it. But how should the child widget tell the stackedwidget that he should change setCurrentIndex? I was not able to do it. Can post my code if that helps.
Thank you for your helpYou have to ask yourself if you really need to use different classes for pages. If not then moving through pages is quite straight forward
connect(ui->pushButton, &QPushButton::released, [this]{ ui->stackedWidget->setCurrentIndex(1); });
if you need to use different classes for pages then you would need to access parent widget
qobject_cast<QStackedWidget *>(parentWidget())->setCurrentIndex(1);
or make connections from class object where you create page objects.
wrote on 3 May 2017, 11:49 last edited by Lunarix 5 Mar 2017, 12:46@Eligijus
Your secound idea works great!
I've one last question:
If I am in the settings screen and if I make changes in a QComboBox there, let's say a number in the menu should change.
So how can I get the data from the settings class to the menu class when I use QStackedWidgets?
here is my code:settings.cpp
void settings::on_pushButton_clicked() { int data = ui->comboBox->currentIndex(); qobject_cast<QStackedWidget *>(parentWidget())->setCurrentIndex(2); qobject_cast<QStackedWidget *>(parentWidget())->settingToGame(data); // This does not work atm }
and in mainwindow.h (which has the QStackedWidgets)
#include <QtGui> #include "form.h" #include "settings.h" #include "game.h" class Form; class settings; class game; class myMainWindow : public QMainWindow { Q_OBJECT public: myMainWindow():QMainWindow() //Construktor { QWidget* centralWidget = new QWidget(); centralWidget->setFixedSize(825,620); m_pStackedWidget = new QStackedWidget(); myForm = new Form(); Ez_settings = new settings(); my_game = new game(); m_pStackedWidget->addWidget(myForm); // 0 m_pStackedWidget->addWidget(Ez_settings); // 1 m_pStackedWidget->addWidget(my_game); // 2 //m_pStackedWidget->setFixedSize(480,300); QVBoxLayout *layout = new QVBoxLayout; layout->addWidget(m_pStackedWidget); setCentralWidget(centralWidget); setWindowTitle("Die Siedler von Catan"); centralWidget->setLayout(layout); //setFixedSize(800,600); }; ~myMainWindow(){ // Destruktor }; private: QStackedWidget* m_pStackedWidget; Form* myForm; settings* Ez_settings; game * my_game; public: void settingToGame(int data){ my_game->data = data; } }; }
and my_game is a widget which is accessed with setCurrentIndex(2) and has a public variable data.
if I change
qobject_cast<QStackedWidget *>(parentWidget())->settingToGame(data);
to
qobject_cast<myMainWindow *>(parentWidget())->settingToGame(data);
"The program has unexpectedly finished."
So how to get the data there?
Thanks for the help! Already helped me a lot
Lunarix -
wrote on 3 May 2017, 12:53 last edited by Lunarix 5 Mar 2017, 12:54
OK - so now I use
qobject_cast<game *>(parentWidget())->settingToGame(data);
and I have the settingToGame now in the game class:
void game::settingToGame(int data){ std::cout << data <<std::endl; // works std::cout << mydata <<std::endl; // crash this->mydata = data; // crash
But this crashes. I can access data, but not view/change mydata which is in the game.h as public: int mydata; and in the constructor mydata=0 declared.
Why can't I get the mydata there? -
wrote on 3 May 2017, 13:03 last edited by
Well if you want to transfer data between objects that come from one root object then only way to do it is through signals and slots or callbacks.
I have made small example that should clear your questions. https://github.com/Ravenghost/ExampleQt
Also I don't recommend adding another class for every page like shown in my example (Segment class) just stick to one class(RootWidget) because it makes things way too complicated as you will see from my example. But if you really need to use multiple classes for pages then do something like I did and put QStackedWidget inside QStackedWidget. -
wrote on 3 May 2017, 14:38 last edited by
@Eligijus
Thanks for the code. I'll have a look.
I understand that many classes cause many problems - So:If I use 1 class: Can I change the whole .ui if I press a button so it looks completly different (e.a. menu and game screen). But it all is in one class and then has different buttons for each .ui ?
-
@Eligijus
Thanks for the code. I'll have a look.
I understand that many classes cause many problems - So:If I use 1 class: Can I change the whole .ui if I press a button so it looks completly different (e.a. menu and game screen). But it all is in one class and then has different buttons for each .ui ?
1/21