Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QMenuBar disappearing on setLayout

QMenuBar disappearing on setLayout

Scheduled Pinned Locked Moved Unsolved General and Desktop
5 Posts 4 Posters 1.4k Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • NeptefreN Offline
    NeptefreN Offline
    Neptefre
    wrote on last edited by
    #1

    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/MlinConsole

    Thanks in advance.

    1 Reply Last reply
    0
    • kshegunovK Offline
      kshegunovK Offline
      kshegunov
      Moderators
      wrote on last edited by
      #2

      @Neptefre

      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 or protected 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 the QApplication::instance static function or through the qApp macro that Qt defines for you.

      Read and abide by the Qt Code of Conduct

      NeptefreN 1 Reply Last reply
      0
      • kshegunovK kshegunov

        @Neptefre

        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 or protected 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 the QApplication::instance static function or through the qApp macro that Qt defines for you.

        NeptefreN Offline
        NeptefreN Offline
        Neptefre
        wrote on last edited by
        #3

        @kshegunov Sorry for the late reply.

        I subclassed the layout for the menu because of how the menu works in this program:

        1. I set the menu's layout (startUpMenu) as the default layout (for MainWindow) on start up.
        2. If "New Game" is clicked, "MainWindow::startGame()" is invoked.
        3. 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?

        1 Reply Last reply
        0
        • A Offline
          A Offline
          alex_malyu
          wrote on last edited by
          #4

          @Neptefre said:

          destructor for startUpMenu is called,

          @kshegunov mentioned normally you do not call destructor explicitly.
          If you create startUpMenu with

          startUpMenu = new .....

          you delete it with
          delete startUpMenu;

          1 Reply Last reply
          0
          • mrjjM Offline
            mrjjM Offline
            mrjj
            Lifetime Qt Champion
            wrote on last edited by
            #5

            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

            1 Reply Last reply
            0

            • Login

            • Login or register to search.
            • First post
              Last post
            0
            • Categories
            • Recent
            • Tags
            • Popular
            • Users
            • Groups
            • Search
            • Get Qt Extensions
            • Unsolved