سؤال

بادئ ذي بدء، أنا مبرمج ذ ذوي الخبرة ولكن جديد في بيثون. أريد إنشاء تطبيق بسيط في Python باستخدام Pyqt. دعونا نتخيل هذا التطبيق هو بسيط كما هو الحال عندما يتم تشغيله، يجب أن تضع أيقونة في علبة النظام وتقديم خيار في قائمةه للخروج من التطبيق.

يعمل الرمز هذا، إنه يظهر القائمة (لا أقوم بتوصيل إجراء الخروج وما إلى ذلك للحفاظ عليه بسيطا)

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

ولكن هذا لا:

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

ربما أفتقد شيئا. لا توجد أخطاء ولكن في الحالة الثانية عندما انقر فوق الزر الأيمن، لا تظهر القائمة.

هل كانت مفيدة؟

المحلول

حسنا، بعد بعض تصحيح الأخطاء وجدت المشكلة. كائن Qmenu يتم تدميره بعد النهاية __init__ وظيفة لأنها لا تملك أحد الوالدين. في حين أن الوالد من QsysterTrayon يمكن أن يكون كائن ل QMENU يجب أن يكون Qwidget. يعمل هذا الرمز (انظر كيف يحصل Qmenu على نفس الوالدين مثل QsySTERTRAYICON وهو 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()

نصائح أخرى

أعتقد أنني أفضل ما يبدو أنه لا يبدو أنه يعتمد على قرارات جمع القمامة الداخلية في 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()

هنا هو الرمز مع تنفيذ إجراء الخروج

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

فيما يلي نسخة PYQT5 (تمكنت من تنفيذ إجراء الخروج من إجابة DemoSthenes).مصدر للتنفيذ من pyqt4 إلى pyqt5

import sys
from PyQt5 import QtCore, QtGui, QtWidgets
# code source: https://stackoverflow.com/questions/893984/pyqt-show-menu-in-a-system-tray-application  - add answer PyQt5
#PyQt4 to PyQt5 version: https://stackoverflow.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)

مع حدث 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()

لم أستطع الحصول على أي من الإجابات المذكورة أعلاه للعمل في PYQT5 (الخروج في قائمة علبة النظام، لن يتم الخروج فعليا)، لكنني تمكنت من الجمع بينها للحل الذي يعمل. ما زلت أحاول تحديد ما إذا كان يجب استخدام التجريد بطريقة أو بأخرى.

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)
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top