I'm having trouble understanding the shortcut functionality of a QAction added to a QMenu. Lets start with an example:
from PyQt4 import QtCore, QtGui
import sys
class TestApp(QtGui.QMainWindow):
def __init__(self, *args):
super(TestApp, self).__init__(*args)
#create contex menu
self.menu = QtGui.QMenu(self)
self.menu.addAction("testEntry", self.action, "CTRL+T")
self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.customContextMenuRequested.connect(self.execContextMenu)
def execContextMenu(self, point):
self.menu.exec_(self.mapToGlobal(point))
def action(self):
print 'action called!'
app = QtGui.QApplication(sys.argv)
win = TestApp()
win.show()
app.exec_()
I would expect action() to be called either when the users presses "Ctrl+T" or when "Ctrl+T" is pressed after the context menu was invoked. But nothing happens when I press the shortcut. However when I add the QAction to the TestApp
act = self.menu.addAction("testEntry", self.action, "CTRL+T")
self.addAction(act)
it works (although it doesn't when the context menu is open). So what am I doing wrong?
I'm using PyQt4 on an OSX 10.6
Thanks for any help ;)
On Mac Qt maps the control key to Meta rather than Ctrl
Related
Normally in Qt applications you would use this at the start and end of your code:
app = QtWidgets.QApplication(sys.argv)
...
app.exec_()
But in Maya, you don't use this because Qt runs on the Maya application it self. I'm sure this works the same for many other applications as well if you don't know what Maya is. That said, my code looks like this:
import sys
from PySide2 import QtWidgets, QtGui, QtCore
class Test():
def __init__(self):
self.open_qt()
def open_qt(self):
# app = QtWidgets.QApplication(sys.argv) # Don't need this in Maya
self.window = QtWidgets.QWidget() # I tried QDialog also
btn = QtWidgets.QPushButton("press me")
btn.clicked.connect(self.login)
lay = QtWidgets.QVBoxLayout()
lay.addWidget(btn)
self.window.setLayout(lay)
self.window.show()
# app.exec_() # Don't need this in Maya
def login(self):
print("logged in!")
print("before")
temp = Test()
print("after")
But running this in Maya I get this result:
before
after
logged in!
But I need it to be:
before
logged in!
after
If you run this code outside of Maya (and you use those two commented out lines) then you get the correct result (block above here).
How can I get the Maya Qt to also wait correctly like it would if you used QtWidgets.QApplication(sys.argv)?
A QDialog might be more well suited for your needs, as it runs its own event loop that won't block the program, while waiting for the dialog to be completed.
The important thing to do is to call of its exec_() and call accept() when needed.
from PySide2 import QtWidgets, QtGui, QtCore
class Test(QtWidgets.QDialog):
def __init__(self, parent=None):
super(Test, self).__init__(parent)
layout = QtWidgets.QVBoxLayout(self)
self.spinBox = QtWidgets.QSpinBox()
layout.addWidget(self.spinBox)
btn = QtWidgets.QPushButton("press me")
layout.addWidget(btn)
btn.clicked.connect(self.login)
def login(self):
print("logged in!")
self.accept()
dialog = Test()
if dialog.exec_():
print(dialog.spinBox.value())
I don't have Maya, but according to this answer you can get its main window using the maya.OpenMayaUI module and shiboken's wrapInstance().
Okay... This has been bugging me for hours. I have a qtmainwindow with a menubar. I've managed to connect an action in tje menubar to an independent Qwidget. But as soon as the Qwidget appears it disappears. I'm using the latest version of pyqt.
Here's the code:
Import sys
from PyQt4 import QtGui, QtCore
Class Main(QtGui.QtMainWindow) :
def __init__(self) :
QtGui.QtMainWindow.__init__(self)
self.setGeometry(300,300,240,320)
self.show()
menubar = self. menuBar()
filemenu = menubar. addMenu('&File')
new = QtGui.QAction(QtGui.QIcon('new.png'), 'New', self)
new.triggered.connect(self.pop)
filemenu.addAction(new)
def pop(self) :
pop = Pop()
class Pop(QtGui.QWidget) :
def __init__(self) :
QtGui.QWidget.__init__(self)
self.setGeometry(300,300,240,320>
self.setWindowTitle('Pop up')
self.show()
Update the pop(self) method as:
def pop(self):
self.window = Pop()
you need to store object of newly created window in a member variable, other wise as soon as the method finishes with the execution, local variables will be destroyed by the Python Garbage Collector.
if you implement this code, you will see the window gets created and disappears immediately.
import sys
from PyQt5 import QtGui, QtWidgets,QtCore
from PyQt5.QtWidgets import QApplication, QMainWindow
app = QtWidgets.QApplication(sys.argv)
window = QtWidgets.QWidget()
window.setGeometry(50,50,500,500)
window.setWindowTitle("GUI window")
window.show()
To solve that problem write "sys.exit(app.exec_())" after window.show() and the window will stay on the screen.
In the below mentioned example when I click on 'Help' submenu under 'View' menu multiple times its creating multiple windows. Can anyone tell me how to resolve this issue?
import sys
from PySide import Qt Gui
from PySide.QtCore import Qt
class Window(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.menu_bar()
def menu_bar(self):
helpAction = QtGui.QAction('&Help', self)
helpAction.setShortcut('Ctrl+H')
helpAction.triggered.connect(self.add_helpWindow)
menu = self.menuBar().addMenu('View')
menu.addAction(helpAction)
def add_helpWindow(self):
window = QtGui.QMainWindow(self)
window.setWindowTitle('New Window')
window.show()
if __name__ == '__main__':
import sys
app=QtGui.QApplication.instance()
if not app:
app = QtGui.QApplication(sys.argv)
window = Window()
window.resize(300, 300)
window.show()
sys.exit(app.exec_())
You help window is just a QMainWindow, which is not modal and there are no restrictions on the number that can exist. Hence why if you select the help option multiple times, you get multiple windows.
You likely want to use a QMessageBox which has its modal property set. While there is nothing forcing only one dialog to exist at a time, being modal means that the use can only interact with that window so long as it is open. Example:
from Pyside.QtGui import QMessageBox
def add_helpWindow(self):
help_dialog = QMessageBox.information(self, 'Help', 'Some Help Text Here')
help_dialog.setModal(True)
return help_dialog.exec_()
You can also get a more generic dialog box using QDialog, which is the parent class of QMessageBox.
If that's not the behavior you want, you'll need to manually track whether the user has opened that window before, and then connect a signal that is emitted when the user closes the help window to a slot that reset the existence tracker. Here is an example using a non-modal QDialog:
from Pyside.QtGui import QDialog
class Window(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.menu_bar()
self.help_open = False # Tracks if the help dialog is already open
def help_closed(self):
self.help_open = False
...
def add_helpWindow(self):
if not self.help_open:
self.help_open = True
help_dialog = QDialog(self)
# Any other setup code here
help_dialog.setModal(False)
help_dialog.accepted.connect(self.help_closed)
help_dialog.rejected.connect(self.help_closed)
help_dialog.show()
I have a PyQt wizard that includes a dialog box that asks the user a question. This dialog box is optional and only for use if the user wants it. A button sends a signal that the app receives and opens the window. The problem I have is that when the dialog is closed, it closes the whole app with it. How do I make sure that when the dialog is closed, the main app stays open and running? Here the code that handles the dialog box:
def new_item(self):
app = QtGui.QApplication(sys.argv)
Dialog = QtGui.QDialog()
ui = Ui_Dialog()
ui.setupUi(Dialog)
Dialog.exec_()
I tried adding a 'Cancel' button to close it manually but the result was the same, the whole app closed.
QtCore.QObject.connect(self.cancel, QtCore.SIGNAL(_fromUtf8("clicked()")), Dialog.close)
You shouldn't create new QApplication objects in your code, and I am not surprised that destroying that object closes the application.
Your code should look something like this:
#!/usr/bin/env python
#-*- coding:utf-8 -*-
from PyQt4 import QtGui, QtCore
class MyWindow(QtGui.QWidget):
def __init__(self, parent=None):
super(MyWindow, self).__init__(parent)
self.dialog = QtGui.QMessageBox(self)
self.dialog.setStandardButtons(QtGui.QMessageBox.Ok | QtGui.QMessageBox.Cancel)
self.dialog.setIcon(QtGui.QMessageBox.Question)
self.dialog.setText("Click on a button to continue.")
self.pushButtonQuestion = QtGui.QPushButton(self)
self.pushButtonQuestion.setText("Open a Dialog!")
self.pushButtonQuestion.clicked.connect(self.on_pushButtonQuestion_clicked)
self.layoutHorizontal = QtGui.QHBoxLayout(self)
self.layoutHorizontal.addWidget(self.pushButtonQuestion)
#QtCore.pyqtSlot()
def on_pushButtonQuestion_clicked(self):
result = self.dialog.exec_()
if result == QtGui.QMessageBox.Ok:
print "Dialog was accepted."
elif result == QtGui.QMessageBox.Cancel:
print "Dialog was rejected."
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
app.setApplicationName('MyWindow')
main = MyWindow()
main.show()
sys.exit(app.exec_())
Try to use Dialog.reject instead of Dialog.close
.close() method is being used mith QMainWindow Widget, .reject() with QDialog.
In my case, I had QSystemTrayIcon as an "entry point" to my app instead of QMainWindow or QWidget.
Calling .setQuitOnLastWindowClosed(False) on my main QApplication instance helped, thanks to this answer
I'm a beginner in PyQt. I was trying to create a simple app to try some of the toolkit's many features. My question is, how can I hide the app icon from the taskbar?
I don't want the user to be able to see the icon in taskbar and to minimize it using this icon. Is there any window flags that I can use to achieve this?
This should do the trick:
myApp.setWindowFlags(QtCore.Qt.Tool)
This drove me nuts for days. Complete app code to implement below.
Key bits:
override closeEvent(), enabling it to do either of just hiding window
or true exit
create some facility for user to choose either hide or
exit behavior
don't show() main window on instantiation, just exec_() the App
import sys
from PyQt4.QtGui import QAction, QApplication, QFrame, QIcon, \
QMainWindow, QMenu, QSystemTrayIcon
from PyQt4.QtCore import SIGNAL
class MyApp(QMainWindow):
def __init__(self, parent, title):
super(QMainWindow, self).__init__(parent)
self.exitOnClose = False
exit = QAction(QIcon(), "Exit", self)
self.connect(exit, SIGNAL("triggered()"), self.exitEvent)
self.trayIcon = QSystemTrayIcon(QIcon(), self)
menu = QMenu(self)
menu.addAction(exit)
self.trayIcon.setContextMenu(menu)
self.connect(self.trayIcon, \
SIGNAL("activated(QSystemTrayIcon::ActivationReason)"), \
self.trayIconActivated)
self.trayIcon.show()
self.trayIcon.showMessage("MyApp is running!", "Click to open window\nRight click for menu" )
def trayIconActivated(self, reason):
if reason == QSystemTrayIcon.Context:
self.trayIcon.contextMenu().show()
elif reason == QSystemTrayIcon.Trigger:
self.show()
self.raise_()
def closeEvent(self, event):
if self.exitOnClose:
self.trayIcon.hide()
del self.trayIcon
event.accept()
else:
self.hide()
event.setAccepted(True)
event.ignore()
def exitEvent(self):
self.exitOnClose = True
self.close()
if __name__ == "__main__":
app = QApplication(sys.argv)
myapp = MyApp(None, "My System Tray App")
app.exec_()
Adapted from this thread:
import sys
from PyQt4.QtGui import *
if __name__ == '__main__':
app = QApplication(sys.argv)
widget = QWidget()
mainWindow = QMainWindow(widget)
mainWindow.show()
sys.exit(app.exec_())
I wouldn't recommend trying to hide an application's taskbar presence, especially if the application is visible. If you are only trying to prevent minimizing from the taskbar then you can achieve this by creating your top level widget with the following window flags like this:
QWidget *mainWindow = new QWidget(0, Qt::CustomizeWindowHint
| Qt::WindowTitleHint | Qt::WindowSystemMenuHint
| Qt::WindowCloseButtonHint | Qt::WindowMaximizeButtonHint);
If you don't want a maximize flag, you can leave that one out of the list too.
The various window flags that Qt can use are documented here (Qt::WindowFlags).
If you are on Ubuntu with Unity and want to hide an application's icon from the launcher on the left-hand-side, you will probably need Qt.SplashScreen. This worked for me but I don't remember if I also needed Qt.Tool, which is enough on Windows. For the SplashScreen attempt you may have to reimplement the resize functionality as it disables this feature of a QStatusBar (that has a SizeGrip) for example.
Here is a little example to try out window flags.
Just initialise your main window like this self.setWindowFlags(Qt.ToolTip)