Domanda

Prima di tutto, io sono un programmatore C esperto ma nuovo a Python. Voglio creare una semplice applicazione in Python usando PyQt. Immaginiamo questa applicazione è semplice come quando viene eseguito deve mettere un'icona nella barra di sistema e ha offrire un'opzione nel suo menu per uscire dall'applicazione.

Questo codice funziona, mostra il menu (non collegare l'azione di uscita e così via per mantenere le cose semplici)

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()

Ma questo non lo fa:

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()

Probabilmente mi manca qualcosa. Non ci sono errori, ma nel secondo caso quando si fa clic con il tasto destro non mostra il menu.

È stato utile?

Soluzione

Bene, dopo un po 'di debug ho trovato il problema. Il QMenu oggetto viene distrutto dopo la funzione di finitura __init__ perché non ha un genitore. Mentre il genitore di un QSystemTrayIcon può essere un oggetto per la QMenu deve essere un QWidget. Questo funziona codice (vedere come QMenu ottiene lo stesso genitore come il QSystemTrayIcon che è 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()

Altri suggerimenti

Credo che io preferirei il seguente in quanto non sembra dipendere dalle decisioni di raccolta dei rifiuti interni del 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()

Ecco il codice con l'azione di uscita implementato

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()

Con un evento pyqt5 collegato:

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()

non ho potuto ottenere una qualsiasi delle risposte di cui sopra per lavorare in PyQt5 (l'uscita nel menu barra delle applicazioni, non sarebbe in realtà uscita), ma sono riuscito a combinarli per una soluzione che funziona. Sto ancora cercando di determinare se exitAction dovrebbe essere usato ulteriormente in qualche modo.

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)
scroll top