Search code examples
pythonpyqtpyqt5menubarqmainwindow

How to create a menu-bar in a QMainWindow


I am writing a small application using PyQT. I am trying to create a menu bar at the top of the application containing the usual options ("File", "Edit", "Options" etc.) but my toolbar is not appearing when I try to add it to my QMainWindow class. I have looked around but it is not obvious to me what I am doing wrong. Note that I have tried using the QMainWindow.menuBar() method instead of creating a QToolbar, but if I do that the bar remains invisible altogether. Using the code below, I at least get an empty bar, even if it is empty. The code below is a minimal example of this problem. I would like to know what I have to change for the actions to show up.

import sys
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QBrush
from PyQt5.QtWidgets import QMainWindow, QGraphicsScene, QToolBar, QMenu, QAction, QGraphicsView, QApplication


class GraphWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.scene = QGraphicsScene()

        # a grid foreground
        self.scene.setBackgroundBrush(QBrush(Qt.lightGray, Qt.CrossPattern))
        self.grid = True

        # Create upper toolbar with menu options
        tb = QToolBar()
        menu = QMenu()
        db_action = QAction("Open file")
        db_action.setStatusTip("Select a file to use as a database")
        db_action.triggered.connect(self.open_new_db)
        menu.addAction(db_action)

        tb.addWidget(menu)
        tb.setAllowedAreas(Qt.TopToolBarArea)
        tb.setFloatable(False)
        tb.setMovable(False)
        self.addToolBar(tb)

        self.statusBar().showMessage("Ready")

        # Demonstrate the results from the input.

        graphics = QGraphicsView(self.scene)
        self.setCentralWidget(graphics)
        self.showFullScreen()

    def open_new_db(self):
        pass

    def keyPressEvent(self, e):
        # Currently, we respond to a press of the Escape key by closing the program.
        if e.key() == Qt.Key_Escape:
            self.close()

app = QApplication(sys.argv)
gr = GraphWindow()
sys.exit(app.exec_())

Solution

  • To create a menu in the menu bar, you must give it a title. Also, Qt does not take ownership of the menus or actions, so you must either give them a parent or keep a reference to them in some other way, so that they don't get garbage-collected. Your example can be fixed like this:

    class GraphWindow(QMainWindow):
        def __init__(self):
            ...
            # Create menu options
            menubar = self.menuBar()
            menu = QMenu('File', self) # title and parent
            db_action = QAction("Open file", self) # title and parent
            db_action.setStatusTip("Select a file to use as a database")
            db_action.triggered.connect(self.open_new_db)
            menu.addAction(db_action)
            menubar.addMenu(menu)
    
            self.statusBar().showMessage("Ready")
    

    Note that the toolbar is not needed at all. A somewhat shorter and simpler way to achieve the same thing, is to add the menus and actions more directly, like this:

        menubar = self.menuBar()
        menu = menubar.addMenu('File')
        db_action = menu.addAction("Open file")
        db_action.setStatusTip("Select a file to use as a database")
        db_action.triggered.connect(self.open_new_db)
    

    Here, Qt will automatically set the parents wherever required.