QMenuBar disappearing on setLayout
-
I've made a basic board game application, in which the entire game interface is managed in a class I've called "interfaceWindow". It has a QMenuBar (a "gameToolbar" class called "toolbar" in "toolbar.cpp").
Here's the download link for my code: https://github.com/Matulin/MlinConsole
On it's own, the class works perfectly:
(main.cpp) int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w(&a); w.show(); return a.exec(); }
(mainwindow.h) class MainWindow : public QWidget { Q_OBJECT public: explicit MainWindow(QApplication * thisApp, QWidget *parent = 0); QApplication * parentApplication; ~MainWindow(); mainMenu * startUpMenu; public slots: void startGame(); };
(mainwindow.cpp) MainWindow::MainWindow(QApplication * thisApp, QWidget *parent) : QWidget(parent) { parentApplication = thisApp; //startUpMenu = new mainMenu(this); interfaceWindow * w = new interfaceWindow(parentApplication); setLayout(w); } MainWindow::~MainWindow() { } void MainWindow::startGame() { startUpMenu->~mainMenu(); interfaceWindow * w = new interfaceWindow(parentApplication); w->setMenuBar(w->toolbar); setLayout(w); }
This generates what I want. The problem happens when I try to make the game run from a start-up menu (I suggest you download the code from Github and run it before an after the following changes to see what I mean) i.e. when I change it from:
MainWindow::MainWindow(QApplication * thisApp, QWidget *parent) : QWidget(parent) { parentApplication = thisApp; //startUpMenu = new mainMenu(this); interfaceWindow * w = new interfaceWindow(parentApplication); setLayout(w); }
to:
MainWindow::MainWindow(QApplication * thisApp, QWidget *parent) : QWidget(parent) { parentApplication = thisApp; startUpMenu = new mainMenu(this); //interfaceWindow * w = new interfaceWindow(parentApplication); setLayout(startUpMenu); }
startGame() is run when the user clicks "New Game" from the start-up menu. This deletes the current menu and replaces the layout with a new interfaceWindow class.
It successfully starts a new game, but the toolbar at the top doesn't appear. I have no idea why this is happening. I doubt it's a problem with interfaceWindow, since that seems to work without a problem before I add the start-up menu. I've tried manually setting the toolbar in startGame(), but that doesn't seem to do anything.
Here's how I've defined mainMenu:
(menu.h) class mainMenu : public QVBoxLayout { Q_OBJECT public: explicit mainMenu(MainWindow * givenWindow); ~mainMenu(); private: QPushButton * newGame; QPushButton * loadGame; QPushButton * howToPlay; QPushButton * settings; QPushButton * exitButton; MainWindow * parentWindow; };
(menu.cpp) mainMenu::mainMenu(MainWindow * givenWindow) { parentWindow = givenWindow; newGame = new QPushButton("New Game"); loadGame = new QPushButton("Load Game"); howToPlay = new QPushButton("How to Play"); settings = new QPushButton("Settings"); exitButton = new QPushButton("Exit Button"); connect(newGame, SIGNAL(clicked()), parentWindow, SLOT(startGame())); addWidget(newGame); addWidget(loadGame); addWidget(howToPlay); addWidget(settings); addWidget(exitButton); }
The toolbar/QMenubar is defined in toolbar.cpp, and interfaceWindow is defined in interface.cpp. I doubt the problem is there, but just in case you can see the full code here:
https://github.com/Matulin/MlinConsoleThanks in advance.
-
One thing that immediately jumps at me is this line:
startUpMenu->~mainMenu();
Why are you calling the destructor explicitly?! Do you have an in-place
new
somewhere in your code? If not don't do that.Additionally, I don't see a reason why you want to subclass the layout. What would be the purpose of that code? Do you provide a custom laying out technique? If the only reason is to add some widgets to the layout, then just call the methods onto the object after creating it:
QVBoxLayout * layout = new QVBoxLayout; newGame = new QPushButton("New Game"); loadGame = new QPushButton("Load Game"); // ... layout ->addWidget(newGame); layout ->addWidget(loadGame); // ...
Another thing you should do is to protect your members by making them either
private
orprotected
as you'd want to encapsulate the types, not leave them wide open for any other class to modify.
And finally, you don't need to pass the application object along, much less keep a pointer to it. You can retrieve it at any time with theQApplication::instance
static function or through theqApp
macro that Qt defines for you. -
@kshegunov Sorry for the late reply.
I subclassed the layout for the menu because of how the menu works in this program:
- I set the menu's layout (startUpMenu) as the default layout (for MainWindow) on start up.
- If "New Game" is clicked, "MainWindow::startGame()" is invoked.
- In "MainWindow::startGame()", a new layout for the game (interfaceWindow) is generated and set as the layout for MainWindow. Before setting the new layout, the destructor for startUpMenu is called, and the new interfaceWindow is set as the layout for MainWindow. As far as I can tell, there's no way to unset a layout, so I get an error if I try to set the interfaceWindow as the layout of MainWindow without first calling the destructor for the startUpMenu.
To my mind this is the simplest way to navigate between different states of the program. To return to the main menu from the game, I'd just have to create a new startUpMenu and set it as the layout for MainWindow. Is there a better way to do this that I should be doing instead?
-
@Neptefre said:
destructor for startUpMenu is called,
@kshegunov mentioned normally you do not call destructor explicitly.
If you create startUpMenu withstartUpMenu = new .....
you delete it with
delete startUpMenu; -
Hi
Just a thought.
Have you looked at Qstackedwidget?
its perfect for having pages/screens and easy go back and forth.
http://doc.qt.io/qt-5/qstackedwidget.html