How to use Qt classes defined accross multiple files?



  • I'm trying to create my first Qt desktop application. I have managed to create a QMainWindow widget and I am trying to add a menu bar to it. I was able to create a MainWindow with a menu bar that has one menu option. I was able to do this when all my code was in one file, and I was using the MainWindow constructor to set up the whole GUI.

    I now would like to separate my GUI/widgets into separate files for maintainability.
    Here are my current files:
    mainwindow.h

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QMainWindow>
    #include "filesystem.h"
    
    #include "./menu/filemenu.h"
    
    class QString;
    
    class FileMenu;
    
    namespace Ui {
    class MainWindow;
    }
    
    class MainWindow : public QMainWindow {
        Q_OBJECT
    
    public:
        explicit MainWindow(QWidget *parent = 0);
    
        ~MainWindow();
    
    private:
        Ui::MainWindow *ui;
        QString main_title = "";
    
        int width;
        int height;
    
        FileMenu *filemenu;
    
        void setName() {
            this->setWindowTitle(MainWindow::main_title);
        };
    
        void resizeMainWindow();
        void setUp();
    
        // void createMenuBar();
    
    
    };
    
    #endif
    
    

    mainwindow.cpp

    #include <stdlib.h>
    #include <QtWidgets>
    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include <QDesktopWidget>
    #include <QRect>
    
    
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent), ui(new Ui::MainWindow) {
        ui->setupUi(this);
        this->setUp();
        filemenu = new FileMenu(this);
        filemenu->createMenuBar();
    }
    
    MainWindow::~MainWindow(){
        delete ui;
    }
    
    void MainWindow::resizeMainWindow() {
        QRect main_screen = 
       QDesktopWidget().availableGeometry(QDesktopWidget().primaryScreen());
        MainWindow::height = main_screen.height();
        MainWindow::width = main_screen.width();
        this->resize(MainWindow::width, MainWindow::height);
    }
    
    void MainWindow::setUp() {
        this->setName();
        this->resizeMainWindow();
    }
    
    

    ./menu/filemenu.h

    #ifndef FILEMENU_H
    #define FILEMENU_H
    
    #include <QMenu>
    #include <QAction>
    #include <QMenuBar>
    
    #include "../mainwindow.h"
    
    class MainWindow;
    class QMenu;
    class QMenuBar;
    
    class FileMenu: public QMainWindow {
        Q_OBJECT
    
        public:
            FileMenu(MainWindow *p);
            ~FileMenu();
            void createMenuBar();
    
        private:
            MainWindow *parent;
    
            QMenu *fileOption;
            QAction *newFolder;
            QAction *newFile;
            QAction *newWindow;
            QAction *exitWindow;
    
            void createFileActions();
        private slots:
            void openNewFolder();
            void openNewWindow();
            void openNewFile();
            void exitWindow();
    };
    
    #endif
    

    ./menu/filemenu.cpp

    #include "filemenu.h"
    #include <QMainWindow>
    
    FileMenu::FileMenu(MainWindow *p):
        parent(p) {
        //this->createMenuBar();
        this->createFileActions();
    
    }
    
    void FileMenu::createMenuBar() {
        fileOption = menuBar()->addMenu(tr("&File"));
        fileOption->addAction(newWindow);
        fileOption->addAction(newFolder);
        fileOption->addAction(newFile);
    }
    
    
    void FileMenu::createFileActions() {
        newFolder = new QAction(tr("&New Folder"), this);
        newFolder->setShortcut(tr("Ctrl+Shift+N"));
        newFolder->setStatusTip(tr("Create a new folder"));
        connect(newFolder, &QAction::triggered, this, &FileMenu::openNewFolder);
    
        newWindow = new QAction(tr("&New Window"), this);
        newWindow->setShortcut(tr("Ctrl+N"));
        newWindow->setStatusTip("Open a new MTX window");
        connect(newWindow,&QAction::triggered, this, &FileMenu::openNewWindow);
    
        newFile = new QAction(tr("&New File"), this);
        newFile->setShortcut(tr("Shift+N"));
        newFile->setStatusTip("Create a new file");
        connect(newFile, &QAction::triggered, this, &FileMenu::openNewFile);
    
        exitWindow = new QAction(tr("&Exit"), this);
        exitWindow->setShortcut(tr("Shift+C"));
        exitWindow->setStatusTip("Exit MTX");
        connect(exitWindow, &QAction::triggered, this, &FileMenu::openNewFile);
    }
    void FileMenu::exitWindow() {
        exit(EXIT_SUCCESS);
    }
    
    
    FileMenu::~FileMenu() {
        delete newFolder;
        delete newFile;
        delete newWindow;
        delete exitWindow;
    }
    

    However, when I make and run the project when it's structured as above, the main window loads with no menu. What am I doing wrong?

    Thanks for the help.


  • Lifetime Qt Champion

    Hi and welcome to devnet,

    Because you're not looking at the main window you expect. You did not really separate things here actually, you created a separate QMainWindow based class that you put in the main QMainWindow based class but you don't show it.



  • @SGaist Can you expound on this statement? I'm not sure I understand it exactly as you've phrased it.

    You did not really separate things here actually, you created a separate QMainWindow based class that you put in the main QMainWindow based class but you don't show it.

    Thanks.


  • Lifetime Qt Champion

    @MakingTheEight
    Hi
    In the old Mainwindow, you do

    MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent), ui(new Ui::MainWindow) {
    ui->setupUi(this);
    this->setUp();
    filemenu = new FileMenu(this); // new main window
    filemenu->createMenuBar();
    }

    But you do not see FileMenu, but the MainWindow ( i assume).
    
    Please try 
    
    filemenu = new FileMenu(); // new main window dont give parent
    filemenu->createMenuBar();
    filemenu->show();
    

    You should see you actually have 2 MainWindows :)

    I assume you want to use FileMenu as the new MainWindow ?

    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        a.setStyleSheet( yourstylesheet );
        MainWindow w; // use FileMenu here instead
        w.show();
    
        return a.exec();
    }
    
    

  • Qt Champions 2018

    @MakingTheEight

    class MainWindow : public QMainWindow {
    ...
    class FileMenu: public QMainWindow {
    

    Do you realise that you create TWO QMainWindows?
    Why is FileMenu derived from QMainWindow?



  • @jsulm I have tried to have FileMenu inherit from QMenu but I get the following error.
    error: ‘menuBar’ was not declared in this scope.

    My idea was to have FileMenu inherit QMenu from QMainWindow. How would you suggest I solve my problem.

    Thanks for the hel


  • Lifetime Qt Champion

    Remove the use of menuBar from it and pass the FileMenu instance to your MainWindow status bar.



  • @jsulm @mrjj @ig Thanks for all the help.
    I was able to fix the inheritance issue by creating a new FileMenu instance in the main window.



Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.