Question

I'm clearly missing something here; why doesn't the File menu get added in this little example app?

import sys
from PySide.QtGui import *

class Window(QMainWindow):
    def __init__(self):
        super(Window, self).__init__()
        self.setWindowTitle('Test')
        layout = QHBoxLayout()
        self.widget = QWidget()
        self.widget.setLayout(layout)
        self.setCentralWidget(self.widget)
        self.exitAction = QAction('Exit', self, shortcut=QKeySequence.Quit, triggered=self.close)
        self.fileMenu = self.menuBar().addMenu('File')
        self.fileMenu.addAction(self.exitAction)

app = QApplication(sys.argv)
w = Window()
w.show()
sys.exit(app.exec_())

EDIT:

Ok, it looks like this is actually a unicode issue. Here's another example app:

from __future__ import unicode_literals, print_function, division
import sys
from PySide.QtCore import *
from PySide.QtGui import *

class Window(QMainWindow):
    def __init__(self):
        super(Window, self).__init__()
        self.dummyAction = QAction(self.tr('dummy'), self, triggered=self.dummy)
        self.gameMenu = self.menuBar().addMenu(self.tr('ddddummy'))
        print (self.tr('dummy'))
        self.gameMenu.addAction(self.dummyAction)
        layout = QHBoxLayout()
        self.widget = QWidget()
        self.widget.setLayout(layout)
        self.setCentralWidget(self.widget)

    def dummy(self):
        pass

locale = QLocale.system().name()
qtTranslator = QTranslator()
app = QApplication(sys.argv)
if qtTranslator.load('qt_' + locale, ':/'):
    app.installTranslator(qtTranslator)
w = Window()
w.show()
sys.exit(app.exec_())

This app doesn't have 'File' or 'Quit' or 'Exit' -- but it works if I comment out the from __future__ line, or surround the quoted strings like self.tr(str('foo')) instead of self.tr('foo')

EDIT 2:

from __future__ import unicode_literals
import sys
from PySide.QtGui import *

class Window(QMainWindow):
    def __init__(self):
        super(Window, self).__init__()
        print self.tr('foo')

app = QApplication(sys.argv)
Window().show()
sys.exit(app.exec_())

This should print 'foo', but prints nothing.

Was it helpful?

Solution

At first glance, your code seems perfectly normal, and it does function just as expected on windows or linux. The issue here is that on OSX, the operating system enforces a standard interface on the menu. Whereas on other operating systems the menu is nested right under your app, and your app owns it...on OSX, the operating system owns it. Hence it is shown in the global menu area.

That being said, OSX is filtering out some reserved keywords like "Quit" or "Exit". The reason for this is because the quit functionality is a standard that is automatically placed in your Application menu. When you run it as a basic python script, the menu will be called "Python". But if you bundle it into an app, it will be named accordingly for your bundled app.

This link here, while not an exact explanation, does mention the differences for a menu on OSX.

For a quick example of fixing your menu, see what happens when you do:

    self.exitAction = QAction('Kwit', self)

OSX will not filter out that one. But I suppose its better to follow the native standards which make all app experiences the same on the platform. You would definitely include the "Quit" menu action as you have it now, so that your app will be cross-platform if run on linux or windows and just expect that OSX will relocate it for you.

OTHER TIPS

I've come across this thread because I'm struggling with a similar issue. Here's what I've found...

About your EDIT 2: Your code will correctly print 'foo' if you substitute the line

Window().show()

for the lines

w = Window()
w.show()

as you had in your original code. Apparently the return type on the constructor causes chaining to be an issue in python?

I was able to reproduce your EDIT 1 by commenting out the from __future__ line. Otherwise, the code below works as expected in OS X (Mountain Lion 10.8.3 with brewed python). Specifically, the following code puts the "About" action under the "Python" application menu that OS X creates, and also creates a "Help" menu containing the "Website" action.

import sys
from PySide.QtGui import QApplication,QMainWindow, QWidget, QAction

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

    def create_menus(self):
        self.aboutAction = QAction('About', self, triggered=self.on_about)
        self.websiteAction = QAction('Website', self, triggered=self.on_website)
        self.help_menu = self.menuBar().addMenu('Help')
        self.help_menu.addAction(self.aboutAction)
        self.help_menu.addAction(self.websiteAction)

    def create_main_frame(self):
        self.mainWidget = QWidget()
        self.setCentralWidget(self.mainWidget)

    def on_website(self):
        pass

    def on_about(self):
        pass

app = QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())

I should draw attention to an important point that this thread helped me discover. I've seen a lot of advice for OS X that indicates you should create menu_bar = QMenuBar() independently of QMainWindow and then bind with self.setMenuBar(menu_bar) where self represents QMainWindow. This, in fact, didn't work for me. Instead, what did work, is grabbing the menu bar reference directly from the QMainWindow class itself. For example, and like above, when adding a menu, use self.help_menu = self.menuBar().addMenu('Help') as above.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top