Is there a way to change default menu title for native menu on MacOS for a simple pyqt5 app?
I'm trying to change "Python" menu entry on above image. Is there a way to rename it? Can I hide it somehow?
This code prints only "File":
menubar = self.menuBar()
for item in menubar.actions():
print(item.text())
menubar.setNativeMenuBar(False) doesn't help too (just move "File" into the MainWindow).
Update Sample app code:
from PyQt5 import QtCore, QtWidgets, uic
import sys
class Ui(QtWidgets.QMainWindow):
def __init__(self):
super(Ui, self).__init__()
# QtCore.QCoreApplication.setApplicationName('QtFoo') # doesn't work
uic.loadUi('App.ui', self)
self.show()
# app = QtWidgets.QApplication(sys.argv)
app = QtWidgets.QApplication(["MyCoolApp"])
# app.setApplicationName("QtFoo") # doesn't work
# app.setApplicationDisplayName("Display Name")
window = Ui()
app.exec()
If you are not willing to package your app, you could create a temporary symbolic link to python as described here. This link can be used to execute python apps while displaying a custom name in the title bar:
go to the location of your app (e.g. my_app.py) file in the terminal
create symbolic link (replace location to your python interpreter, replace "BeautifulNaming" with desired name)
ln -s /Users/Christian/miniconda3/bin/python BeautifulNaming
call link to python with your script
./BeautifulNaming my_app.py
The "python" in the system menu bar appears because you run the script from the python, as soon as you package the application the title will disappear. For example the following code
# FileName PyQt5MenuProblem.py
import sys
from PyQt5.QtWidgets import QApplication,QMainWindow
class AppTest(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.setWindowTitle("My application")
self._createMenuBar()
def _createMenuBar(self):
self.menuBar = self.menuBar()
self.menuBar.setNativeMenuBar(False)
fileMenu = self.menuBar.addMenu("&File")
editMenu = self.menuBar.addMenu("&Edit")
if __name__== "__main__":
app = QApplication(sys.argv)
plotWindow = AppTest()
plotWindow.showMaximized()
sys.exit(app.exec_())
after packaging with
pyinstaller --onefile PyQt5MenuProblem.py
looks like
Key words: MacOS, User Interface, LSUIElement, pyinstaller, pyqt5
Related
I am learning pyqt5 and somehow I can't use fcitx in the text box created by QTextEdit or QLineEdit although fcitx works normally with other Qt apps like goldendict or kate. But later I found out that fcitx also doesn't work with another Qt app named Retext which uses Qt 5.10. Maybe this has something to do with the latest version of Qt or so I think.
Here's my code, just a simple textbox and nothing else:
import PyQt5.QtWidgets as QtWidgets
import sys
class App(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.text = QtWidgets.QTextEdit()
self.initUI()
def initUI(self):
vbox = QtWidgets.QVBoxLayout()
vbox.addWidget(self.text)
self.setLayout(vbox)
self.show()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())
Thanks to #ekhumoro, I know how to fix this. Just enable input method by adding this line to the __init__ function:
self.setAttribute(Qt.WA_InputMethodEnabled)
Then do this:
cp /usr/lib/x86_64-linux-gnu/qt5/plugins/platforminputcontexts/fcitxplatforminputcontextplugin.so ~/.local/lib/python3.6/site-packages/PyQt5/Qt/plugins/platforminputcontexts
sudo chmod +x ~/.local/lib/python3.6/site-packages/PyQt5/Qt/plugins/platforminputcontexts/fcitxplatforminputcontextplugin.so
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.
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.
https://stackoverflow.com/a/11387977/5362866
http://doc.qt.io/qt-5/qmenubar.html#qmenubar-as-a-global-menu-bar
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_())
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".
try this:
menubar = QMenuBar()
self.setMenuBar(menubar)
instead of menubar = self.menuBar()
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()
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.
Disclaimer: New to both python and qt designer
QT Designer 4.8.7
Python 3.4
PyCharm 5.0.3
Question - How do I add controls to the main form or a scroll area widget on the main form (created in QT Designer) programmatically?
I have created a MainWindow in qt designer and added my widgets. The following is the entire test program in PyCharm:
import sys
from PyQt4 import QtGui, QtCore, uic
from PyQt4.QtGui import *
from PyQt4.QtCore import *
qtCreatorFile = "programLauncher.ui"
Ui_MainWindow, QtBaseClass = uic.loadUiType(qtCreatorFile)
class MyApp(QtGui.QMainWindow, Ui_MainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
Ui_MainWindow.__init__(self)
self.setupUi(self)
# Cannot resize or maximize
self.setFixedSize(1045, 770)
# Add button test
self.dateLabel = QtGui.QLabel("Test")
self.pushButton = QtGui.QPushButton('Test button')
# self.scrollArea_programs.addWidget()
grid = QtGui.QGridLayout()
# self.scrollArea_programs.addWidget(self.pushButton)
grid.addWidget(self.dateLabel,0,0)
grid.addWidget(self.pushButton,0,1)
self.setLayout(grid)
self.pushButton_exit.clicked.connect(self.closeEvent)
def closeEvent(self):
QtGui.QApplication.quit()
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
window = MyApp()
window.show()
sys.exit(app.exec_())
As you can see I tried to add controls to a grid but nothing shows up when the program runs - I have also tried to add a control to the scroll area. Can someone help me to just add 1 control to the scroll area at run time - so then I can know the proper way to do it or "a" proper way to do this.
Thanks in advance
Without having access to your programLauncher.ui and making minimal changes to your posted code, you can add your UI elements to the window like so:
from PyQt4 import QtGui
import sys
class MyApp(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
# Cannot resize or maximize
self.setFixedSize(1045, 770)
widget = QtGui.QWidget(self)
self.setCentralWidget(widget)
# Add button test
self.dateLabel = QtGui.QLabel("Test")
self.pushButton = QtGui.QPushButton('Test button')
grid = QtGui.QGridLayout()
grid.addWidget(self.dateLabel, 0, 0)
grid.addWidget(self.pushButton, 0, 1)
widget.setLayout(grid)
self.pushButton.clicked.connect(self.closeEvent)
def closeEvent(self, event):
QtGui.QApplication.quit()
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
window = MyApp()
window.show()
sys.exit(app.exec_())
This will get the controls on the screen, although the layout leaves a lot to be desired. You may have to make modifications to this based on what's in your .ui file. One thing that you'll want to note in this example is that the QMainWindow needs a central widget (widget in the example above). You then set the layout on that widget.
You can use the designer to create your .ui file
The you can load it in your .py using something like:
from PyQt4 import QtCore, QtGui, uic
class my_win(QtGui.QMainWindow):
def __init__(self):
self.ui = uic.loadUi('my_ui.ui',self)
then you can access all your widgets with something like
self.ui.actionQuit.triggered.connect(QtGui.qApp.quit)
or
self.ui.my_button.triggered.connect(self.do_someting)
Thanks to JCVanHamme (the programLauncher.ui hint) and also outside help I now learned most of what I need to know to access MainWindow at run time. So for anyone interested in this beginner tip:
Take a blank form in QT Designer
Add a control
Run pyuic4 batch file
Take a look at the generated .py file to learn EVERYTHING about how to add controls.
Don't let the power go to your head - cheers
This example creates a single QListWidget with its items right-click enabled.
Right-click brings up QMenu. Choosing a menu opens a OS File Browser in a current user's home directory.
After a File Browser is closed QMenu re-appears which is very annoying.
How to avoid this undesirable behavior?
import sys, subprocess
from os.path import expanduser
from PyQt4 import QtGui, QtCore
class Window(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
layout = QtGui.QVBoxLayout(self)
self.listWidget = QtGui.QListWidget()
self.listWidget.addItems(('One','Two','Three','Four','Five'))
self.listWidget.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.listWidget.connect(self.listWidget,QtCore.SIGNAL('customContextMenuRequested(QPoint)'),self.showMenu)
self.menu=QtGui.QMenu()
menuItem=self.menu.addAction('Open Folder')
self.connect(menuItem,QtCore.SIGNAL('triggered()'),self.openFolder)
layout.addWidget(self.listWidget)
def showMenu(self, QPos):
parentPosition=self.listWidget.mapToGlobal(QtCore.QPoint(0, 0))
menuPosition=parentPosition+QPos
self.menu.move(menuPosition)
self.menu.show()
def openFolder(self):
if sys.platform.startswith('darwin'):
subprocess.call(['open', '-R',expanduser('~')])
if sys.platform.startswith('win'):
subprocess.call(['explorer','"%s"'%expanduser('~')])
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
Two ideas come to my mind:
Try adding self as a constructor parameter when defining QMenu(), passing your QWidget as a parent.
Call self.menu.hide() in the openFolder() method.
Tip: instead of using subprocess to open up explorer, there's an arguably better, cross platform solution in Qt called QDesktopServices - see http://pyqt.sourceforge.net/Docs/PyQt4/qdesktopservices.html
In the minimal example given below, the context menu (right click on white section of the gui) is displayed only briefly and then disappears. This is the case if the app is started from the IPython (0.13.1) console. When started normally from shell it works as it should.
import sys
from PySide import QtGui, QtCore
from IPython.lib.guisupport import get_app_qt4, start_event_loop_qt4
class ContextTestGui(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.ui = Ui_ContextTestWindow()
self.ui.setupUi(self)
self.ui.treeView.addAction(self.ui.actionCopy)
self.ui.treeView.addAction(self.ui.actionShow)
class Ui_ContextTestWindow(object):
def setupUi(self, ContextTestWindow):
ContextTestWindow.resize(200, 100)
self.treeView = QtGui.QTreeView(ContextTestWindow)
self.treeView.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
self.treeView.setMinimumSize(QtCore.QSize(100, 100))
self.actionCopy = QtGui.QAction("Copy",ContextTestWindow)
self.actionShow = QtGui.QAction("Show",ContextTestWindow)
def create_window(window_class,**kwargs):
app = get_app_qt4(sys.argv)
window = window_class()
window.show()
start_event_loop_qt4(app)
return window
if __name__ == '__main__':
simgui = create_window(ContextTestGui)
I believe this is IPython Issue #2380, which should be fixed in current git master.
If you want your app to workaround this bug in 0.13, you will have to ship with your own code a version of IPython/lib/inputhookqt4.py from master, and monkeypatch IPython with:
from IPython.lib import inputhook
inputhook.enable_qt4 = my_enable_qt4
OR, alternatively, just override create_inputhook_qt4
from IPython.lib import inputhookqt4
inputhookqt4.create_inputhook_qt4 = my_create_inputhook_qt4
I expect both approaches should work, as long as you do it before %gui qt is called.
How do you run the application ? In[1]: %run file.py?
I can't reproduce it on ~last master (feb 4 f46bfec 08389b4) with OS X