python - examples - qgridlayout pyqt5
PyQt: Mostrar menú en una aplicación de bandeja de sistema (6)
En primer lugar, soy un programador de C experimentado pero nuevo en Python. Quiero crear una aplicación simple en python usando pyqt. Imaginemos que esta aplicación es tan simple como cuando se ejecuta, tiene que colocar un icono en la bandeja del sistema y ofrece una opción en su menú para salir de la aplicación.
Este código funciona, muestra el menú (no conecto la acción de salida, etc. para mantenerlo simple)
import sys
from PyQt4 import QtGui
def main():
app = QtGui.QApplication(sys.argv)
trayIcon = QtGui.QSystemTrayIcon(QtGui.QIcon("Bomb.xpm"), app)
menu = QtGui.QMenu()
exitAction = menu.addAction("Exit")
trayIcon.setContextMenu(menu)
trayIcon.show()
sys.exit(app.exec_())
if __name__ == ''__main__'':
main()
Pero esto no lo hace:
import sys
from PyQt4 import QtGui
class SystemTrayIcon(QtGui.QSystemTrayIcon):
def __init__(self, icon, parent=None):
QtGui.QSystemTrayIcon.__init__(self, icon, parent)
menu = QtGui.QMenu()
exitAction = menu.addAction("Exit")
self.setContextMenu(menu)
def main():
app = QtGui.QApplication(sys.argv)
trayIcon = SystemTrayIcon(QtGui.QIcon("Bomb.xpm"), app)
trayIcon.show()
sys.exit(app.exec_())
if __name__ == ''__main__'':
main()
Probablemente echo de menos algo. No hay errores, pero en el segundo caso, cuando hago clic con el botón derecho no aparece el menú.
Aquí está el código con la acción Exit implementada.
import sys
from PyQt4 import QtGui, QtCore
class SystemTrayIcon(QtGui.QSystemTrayIcon):
def __init__(self, icon, parent=None):
QtGui.QSystemTrayIcon.__init__(self, icon, parent)
menu = QtGui.QMenu(parent)
exitAction = menu.addAction("Exit")
self.setContextMenu(menu)
QtCore.QObject.connect(exitAction,QtCore.SIGNAL(''triggered()''), self.exit)
def exit(self):
QtCore.QCoreApplication.exit()
def main():
app = QtGui.QApplication(sys.argv)
w = QtGui.QWidget()
trayIcon = SystemTrayIcon(QtGui.QIcon("qtLogo.png"), w)
trayIcon.show()
sys.exit(app.exec_())
if __name__ == ''__main__'':
main()
Aquí está la versión de PyQt5 (fue capaz de implementar la acción Exit de la respuesta de demosthenes). Source para portar desde PyQt4 a PyQt5
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
# code source: https://.com/questions/893984/pyqt-show-menu-in-a-system-tray-application - add answer PyQt5
#PyQt4 to PyQt5 version: https://.com/questions/20749819/pyqt5-failing-import-of-qtgui
class SystemTrayIcon(QtWidgets.QSystemTrayIcon):
def __init__(self, icon, parent=None):
QtWidgets.QSystemTrayIcon.__init__(self, icon, parent)
menu = QtWidgets.QMenu(parent)
exitAction = menu.addAction("Exit")
self.setContextMenu(menu)
def main(image):
app = QtWidgets.QApplication(sys.argv)
w = QtWidgets.QWidget()
trayIcon = SystemTrayIcon(QtGui.QIcon(image), w)
trayIcon.show()
sys.exit(app.exec_())
if __name__ == ''__main__'':
on=r''''# ADD PATH OF YOUR ICON HERE .png works
main(on)
Bueno, después de un poco de depuración encontré el problema. El objeto QMenu se destruye después de finalizar la función __init__
porque no tiene un padre. Mientras que el padre de un QSystemTrayIcon puede ser un objeto para el QMenu, tiene que ser un Qwidget. Este código funciona (vea cómo QMenu obtiene el mismo padre que QSystemTrayIcon que es un QWidget):
import sys
from PyQt4 import QtGui
class SystemTrayIcon(QtGui.QSystemTrayIcon):
def __init__(self, icon, parent=None):
QtGui.QSystemTrayIcon.__init__(self, icon, parent)
menu = QtGui.QMenu(parent)
exitAction = menu.addAction("Exit")
self.setContextMenu(menu)
def main():
app = QtGui.QApplication(sys.argv)
w = QtGui.QWidget()
trayIcon = SystemTrayIcon(QtGui.QIcon("Bomb.xpm"), w)
trayIcon.show()
sys.exit(app.exec_())
if __name__ == ''__main__'':
main()
Con un evento conectado a pyqt5:
class SystemTrayIcon(QtWidgets.QSystemTrayIcon):
def __init__(self, icon, parent=None):
QtWidgets.QSystemTrayIcon.__init__(self, icon, parent)
menu = QtWidgets.QMenu(parent)
exitAction = menu.addAction("Exit")
self.setContextMenu(menu)
menu.triggered.connect(self.exit)
def exit(self):
QtCore.QCoreApplication.exit()
Creo que preferiría lo siguiente, ya que no parece depender de las decisiones internas de recolección de basura de QT.
import sys
from PyQt4 import QtGui
class SystemTrayIcon(QtGui.QSystemTrayIcon):
def __init__(self, icon, parent=None):
QtGui.QSystemTrayIcon.__init__(self, icon, parent)
self.menu = QtGui.QMenu(parent)
exitAction = self.menu.addAction("Exit")
self.setContextMenu(self.menu)
def main():
app = QtGui.QApplication(sys.argv)
style = app.style()
icon = QtGui.QIcon(style.standardPixmap(QtGui.QStyle.SP_FileIcon))
trayIcon = SystemTrayIcon(icon)
trayIcon.show()
sys.exit(app.exec_())
if __name__ == ''__main__'':
main()
No pude obtener ninguna de las respuestas anteriores para trabajar en PyQt5 (la salida en el menú de la bandeja del sistema, en realidad no saldría), pero logré combinarlas para obtener una solución que funcione. Todavía estoy tratando de determinar si exitAction debería usarse más de alguna manera.
import sys
from PyQt5 import QtWidgets, QtCore, QtGui
class SystemTrayIcon(QtWidgets.QSystemTrayIcon):
def __init__(self, icon, parent=None):
QtWidgets.QSystemTrayIcon.__init__(self, icon, parent)
menu = QtWidgets.QMenu(parent)
exitAction = menu.addAction("Exit")
self.setContextMenu(menu)
menu.triggered.connect(self.exit)
def exit(self):
QtCore.QCoreApplication.exit()
def main(image):
app = QtWidgets.QApplication(sys.argv)
w = QtWidgets.QWidget()
trayIcon = SystemTrayIcon(QtGui.QIcon(image), w)
trayIcon.show()
sys.exit(app.exec_())
if __name__ == ''__main__'':
on=''icon.ico''
main(on)