pythonclasspyqt5qmenuqmenubar

Add more than one Qmenu from other classes in MainWindow


I want a single menubar in my main window and be able to set the menus in the menubar from additional classes. Using the setMenuWidget command will overwrite the first menu option as shown in the code. In the classes where I set up the menu I think I may need to just set up a menu rather than a menubar, then set up the menubar in the main window.

This is what I would l like, which can be achieved by populating a single menubar in a class, though I am trying to avoid this method.

enter image description here

Instead only the second menu is show

enter image description here

import sys
from PyQt5.QtWidgets import QAction, QApplication, QMainWindow
from PyQt5 import QtCore, QtGui, QtWidgets

class ToolBar0(QMainWindow):
    def __init__(self, parent=None):
        QMainWindow.__init__(self)

        bar = self.menuBar() # don't think I need a menubar here
        file_menu = bar.addMenu('menu1')
        one = QAction('one', self)
        two = QAction('two', self)
        file_menu.addAction(one)
        file_menu.addAction(two)


class ToolBar1(QMainWindow):
    def __init__(self, parent=None):
        QMainWindow.__init__(self)

        bar = self.menuBar() # don't think I need a menubar here
        file_menu = bar.addMenu('menu2')
        one = QAction('one', self)
        two = QAction('two', self)
        file_menu.addAction(one)
        file_menu.addAction(two)


class MainWindow(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self, parent=None)

        #should a menubar be set up here?

        #For seting widgets in main window
        self.Tool_Bar0 = ToolBar0(self)
        self.setMenuWidget(self.Tool_Bar0)

        ###menu_bar0 is over written
        self.Tool_Bar1 = ToolBar1(self)
        #self.setMenuWidget(self.Tool_Bar1)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    # creating main window
    mw = MainWindow()
    mw.show()
    sys.exit(app.exec_())

Solution

  • You could use a base class with a method to return either a list of QMenu items containing QAction items or a list of QAction items and then render them in your QMainWindow toolbar in whichever way you want, here is an example:

    import sys
    from PyQt5.QtWidgets import QAction, QApplication, QMainWindow, QMenu
    
    
    class WindowWithToolbar:
        def __init__(self):
            super().__init__()
    
        def menu_items(self)->list:
            pass
    
    
    class Window1(WindowWithToolbar, QMainWindow):
        def __init__(self):
            WindowWithToolbar.__init__(self)
            QMainWindow.__init__(self)
    
            # New menu with actions
            self.menu = QMenu('one')
            self.menu.addActions([QAction('two', self), QAction('three', self)])
    
        def menu_items(self):
            return [self.menu]
    
    
    class Window2(WindowWithToolbar, QMainWindow):
        def __init__(self):
            WindowWithToolbar.__init__(self)
            QMainWindow.__init__(self)
    
        def menu_items(self):
            # Only actions
            return [QAction('three', self), QAction('four', self)]
    
    
    class MainWindow(WindowWithToolbar, QMainWindow):
        def __init__(self):
            QMainWindow.__init__(self, parent=None)
    
            self.window1 = Window1()
            self.window2 = Window2()
    
            self.menu = QMenu('File')
            self.helloAction = QAction('Hello')
            self.menu.addAction(self.helloAction)
    
            self._build_menu()
    
        def menu_items(self)->list:
            return [self.menu]
    
        def _build_menu(self):
            self._add_menu_items(self)
            self._add_menu_items(self.window1)
            self._add_menu_items(self.window2)
    
        def _add_menu_items(self, windowWithToolbar: WindowWithToolbar):
            for menu_item in windowWithToolbar.menu_items():
                if isinstance(menu_item, QMenu):
                    self.menuBar().addMenu(menu_item)
                elif isinstance(menu_item, QAction):
                    self.menuBar().addAction(menu_item)
    
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        mw = MainWindow()
        mw.show()
        sys.exit(app.exec_())