11

I've been developing a GUI using PyQt5 and wanted to include a menu bar. When I went to code this feature, however, my menu wouldn't appear. Figuring my understanding on how to implement menu bars in PyQt5 was off, I looked for a pre-existing example online. With some tweaking I developed the following test case:

import sys
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QApplication, QMainWindow, QMenuBar, QAction, qApp

class Example(QMainWindow):

    def __init__(self):
        super().__init__()

        exitAction = QAction(QIcon('exit.png'), '&Exit', self)
        exitAction.triggered.connect(qApp.quit)

        menubar = self.menuBar()
        fileMenu = menubar.addMenu('&Testmenu')
        fileMenu.addAction(exitAction)

        self.show()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

When I run this, however, Testmenu is nowhere to be found.

I have also tried creating the menu bar (and the rest of my GUI layout) in QTCreator before converting the .ui file to an importable .py using pyuic5. I thought this would eliminate some programming mistake on my end, but the menubar still won't show. Any thoughts?

Edit:

Im running this code using Python 3.5 (Anaconda 4.1) from within a Jupyter notebook, version 4.1. I'm also using a Macbook running os 10.1l, PyQt 5.7 and Qt version 5.7.0.

I've realized that the menu bar will become responsive if I click off the application window and then click back onto the window - effectively unfocusing and the focusing the application. Armed with this information I realized that I am not the first to notice this problem (see https://github.com/robotology/yarp/issues/457). Unfortunately, I'm still not sure how to resolve the issue.

user144153
  • 829
  • 1
  • 12
  • 28
  • [QMenuBar on OS X](http://doc.qt.io/qt-5/qmenubar.html#qmenubar-on-os-x). – ekhumoro Sep 21 '16 at 18:06
  • @ekhumoro I don't understand how that pertains to my issue in PyQt. – user144153 Sep 22 '16 at 12:25
  • This is almost certainly an osx-specific issue. Your example runs fine on linux (and probably on windows too). Since [menus seem to work differently on osx](http://doc.qt.io/qt-5/osx-issues.html#menu-bar), maybe you should spell out *exactly* what you expect to see, and what you actually get. Perhaps some screenshots would be helpful. You should also state the exact version of qt5/pyqt5 you are using. – ekhumoro Sep 22 '16 at 15:16
  • Some similar questions [here](http://stackoverflow.com/q/26027184/984421) and [here](http://stackoverflow.com/q/25261760/984421). – ekhumoro Sep 26 '16 at 15:19
  • This seems to be a macOS specific bug. I'm running into the same behavior using PyQt5, using version 5.7 from python 2.7. I have not found a workaround. – dvj Nov 19 '16 at 22:48
  • As previously mentioned the menu bar will become responsive if I click off the application window and then click back onto the window. I'm wondering if a plausible work around might be to do this programmatically. I'm not sure how this would work though. Maybe by shifting focus to the desktop and then immediately back to the application on launch. The added launch time wouldn't be very noticeable. – user144153 Nov 21 '16 at 02:15

6 Answers6

13

It's not a Qt and PyQt5 Bug.

I think your code is zetcode pyqt5 menubar tutorial. I experienced the exact same problem on Mac OS.

First solution is a trick. Use ' &Exit' instead of '&Exit'. Insert a space at the beginning of '&Exit' like this:

...
# exitAction = QAction(QIcon('exit.png'), '&Exit', self) # Not shown
exitAction = QAction(QIcon('exit.png'), ' &Exit', self)
...

The system-wide menubar of macOS reserves keywords such as "Exit", "Quit", and etc. For the same reason, yurisnm's example code shows only the menu items except "Quit" on Mac OS. Actually "Quit" has TextHeuristicRole, so overrides "Quit " behavior in the Application menu. When you click "Quit python" in "Python" menu, it does not quit and just print "quit triggered".

If you must use that name in other menu(e.g. File, Edit), you need to change the action name like above or use QAction::setMenuRole(...) like this:

...
exitAction = QAction(QIcon('exit.png'), '&Exit', self)
print(exitAction.menuRole()) # It prints "1". QAction::TextHeuristicRole
exitAction.setMenuRole(QAction.NoRole)
...

Please read the following, it will be help you.

hwiorn
  • 146
  • 1
  • 7
13

Menubar isn't visible in PyQt5

bar = self.menuBar()

bar.setNativeMenuBar(False)

file = bar.addMenu("File")

file.addAction("New")

NativeMenuBar property specifies whether or not the menubar should be used as a native menubar on platforms that support it. If this property is true, the menubar is used in the native menubar and is not in the window of its parent, if false the menubar remains in the window.

Sample program

import sys

from PyQt5.QtWidgets import QMainWindow, QAction, qApp, QApplication

from PyQt5.QtGui import QIcon


class Menu(QMainWindow):

    def __init__(self):
        super().__init__()
        self.initUI()


    def initUI(self):               

        exitAct = QAction(QIcon('exit.png'), ' &Quit', self)   

        exitAct.setShortcut('Ctrl+Q')
        exitAct.setStatusTip('Exit application')
        exitAct.triggered.connect(qApp.quit)

        self.statusBar()

        menubar = self.menuBar()
        menubar.setNativeMenuBar(False)
        fileMenu = menubar.addMenu('&File')
        fileMenu.addAction(exitAct)

        bar = self.menuBar()
        file = bar.addMenu("Edit")
        file.addAction("New")

        self.setGeometry(300, 300, 300, 200)
        self.setWindowTitle('Simple menu')    
        self.show()


if __name__ == '__main__':

    app = QApplication(sys.argv)
    ex = Menu()
    sys.exit(app.exec_())
Yevhen Kuzmovych
  • 10,940
  • 7
  • 28
  • 48
Nija I Pillai
  • 1,046
  • 11
  • 13
6

If your program is running on Ubuntu, you may find your menu bar on the top of the screen.

If you want to move menu bar to window's title bar, you can toggle the setting at "System setting / Appearance / Behavior / Show the menus for a window / In the window's title bar".

doosik71
  • 61
  • 1
  • 3
0

try this:

menubar = QMenuBar()
self.setMenuBar(menubar)

instead of menubar = self.menuBar()

  • Ah I didn't think to look for a set method. That gets "Testmenu" to show in the menubar, but the exitAction item is still missing. Shouldn't `fileMenu.addAction(exitAction)` populate the menu? – user144153 Sep 19 '16 at 14:26
  • Yes it should populate the menu. At least it is how I do it in my projects. There must be some other error... did you keep the line `fileMenu = menubar.addMenu('&Testmenu')`? – HiFile.app - best file manager Sep 19 '16 at 15:11
  • yes, I left the line intact. To be clear, when I run the code a menubar is created with a menu labeled 'Testament', but nothing happens when I click on it. It's almost like its frozen, except the window itself (and everything else on my machine) runs fine. – user144153 Sep 19 '16 at 15:48
  • I thought this might be related to the fact I'm working out of a Jupiter Notebook, but I just ran the code from terminal and the same issue arises. – user144153 Sep 19 '16 at 15:49
  • I tested your original code on PyQt5 and PySide and they work just fine. Can you show us also the import statements? – HiFile.app - best file manager Sep 19 '16 at 16:03
  • the imports seem to be fine... what environment are you using? – HiFile.app - best file manager Sep 19 '16 at 16:51
  • Im using Python 3.5 (Anaconda 4.1) and Jupyter 4.1 on a Macbook running os 10.11 – user144153 Sep 19 '16 at 17:42
  • I re-ran the code this morning and got really excited when it worked. I then quit the application and tried to run it again, but the the menubar didn't work this time. I used the same code both times. I noticed this yesterday where it would sporadically work, but then stop during the next run. I don't understand what could cause this kind of issue. I even tried restarting the Jupyter kernel. – user144153 Sep 20 '16 at 12:24
  • using pip to --force-reinstall PyQt5 and python along with condo to force a reinstall of anaconda had no effect. – user144153 Sep 20 '16 at 12:54
0

Have you tried the most simple example in the following link tutorialspoint.

Here is the most simple example.

import sys

from PyQt5.QtWidgets import QHBoxLayout, QAction, QApplication, QMainWindow

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

        bar = self.menuBar()
        file = bar.addMenu("File")
        file.addAction("New")

        save = QAction("Save",self)
        save.setShortcut("Ctrl+S")
        file.addAction(save)

        edit = file.addMenu("Edit")
        edit.addAction("copy")
        edit.addAction("paste")

        quit = QAction("Quit",self)
        file.addAction(quit)
        file.triggered[QAction].connect(self.processtrigger)
        self.setWindowTitle("menu demo")

    def processtrigger(self, q):
        print(q.text()+" is triggered")


def main():
    app = QApplication(sys.argv)
    ex = menudemo()
    ex.show()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()
yurisnm
  • 1,630
  • 13
  • 29
  • 1
    This example works perfectly. My only problem is that its using PyQt4 and not PyQt5. I changed the imports to use PyQt5 and included the extra line `from PyQt5.QtWidgets import *` thinking that the example would still work. Unfornutatly this example won't work with PyQt5. I run into the same issue where the menubar will lad, but clicking on it won't expand the menus. Any ideas where this issue is coming from? – user144153 Sep 22 '16 at 12:22
  • Sir, you just have to change the imports because since PyQt5 they have changed some paths. So try it out.. [ANSWER UPDATED] – yurisnm Sep 23 '16 at 14:19
  • 1
    I had already changed the imports to use `PyQt5` when trying out the above example. The window and menubar in this example will load, but unless I unfocused and then focus the window the menubar is unresponsive. It seams to be an issue specific to Qt or PyQt on Mac OS X – user144153 Sep 23 '16 at 14:27
  • I just tried in Linux and it works totally fine. I also took out the QVBoxLayout because it's not even needed. I'm updating it again and just copy and past to see if it works fine. If it doesn't it's definitely a Mac OS X problem "( – yurisnm Sep 23 '16 at 14:54
0

Under MacOS, an application menu appears at the top of the screen. I managed to get the Quit menu option to appear in the above example by prepending the string "Quit" with a null character as follows:

close = QAction("\0Quit",self)
close.setShortcut("Ctrl+Q")
file.addAction(close)

It seems macOS somehow intercepts the menu items called "Quit" or "Exit". You can happily use "Close" or "Leave" without the workaround.

pete
  • 1
  • 2