PyQt:在系统托盘应用程序中显示菜单

问题描述 投票:0回答:9

首先,我是一名经验丰富的 C 程序员,但对 Python 很陌生。我想使用 pyqt 在 python 中创建一个简单的应用程序。让我们想象一下这个应用程序就像它运行时一样简单,它必须在系统托盘中放置一个图标,并且在菜单中提供了一个退出应用程序的选项。

这段代码有效,它显示了菜单(我没有连接退出操作等以保持简单)

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

我可能错过了什么。没有错误,但在第二种情况下,当我单击右键时,它不显示菜单。

python menu pyqt system-tray
9个回答
32
投票

嗯,经过一番调试,我发现了问题。 QMenu 对象在完成

__init__
函数后被销毁,因为它没有父对象。虽然 QSystemTrayIcon 的父对象可以是 QMenu 的对象,但它必须是 Qwidget。这段代码有效(看看 QMenu 如何获得与 QSystemTrayIcon 相同的父级,QSystemTrayIcon 是一个 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()

8
投票

我想我更喜欢以下内容,因为它似乎不依赖于 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()

8
投票

这是实现退出操作的代码

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

8
投票

这里是 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) 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=r''# ADD PATH OF YOUR ICON HERE .png works main(on)
    

5
投票
我无法在 PyQt5 中得到上述任何答案(系统托盘菜单中的退出,实际上不会退出),但我设法将它们结合起来以获得一个可行的解决方案。我仍在尝试确定是否应该以某种方式进一步使用 exitAction。

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)
    

3
投票
使用 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()
    

2
投票
对于 PySide6: 在 main.py 中:

import sys try: from PySide6 import QtWidgets from PySide6.QtWidgets import QApplication from PySide6.QtGui import (QIcon) from PySide6.QtCore import (QSize) except ImportError as e: print("no pyside6") print("use python.exe -m pip install pyside6") print(str(e)) exit(0) from silnik.mytray import SystemTrayIcon if __name__ == "__main__": app = QApplication(sys.argv) ico = QIcon() ico.addFile(u":/img/brylant_64x64.png", QSize(64, 64)) ico.addFile(u":/img/brylant_16x16.png", QSize(16, 16)) ico.addFile(u":/img/brylant_32x32.png", QSize(32, 32)) ico.addFile(u":/img/brylant_48x48.png", QSize(48, 48)) ico.addFile(u":/img/brylant_128x128.png", QSize(128, 128)) app.setWindowIcon(ico) trayIcon = silnik.mytray.SystemTrayIcon(ico) app.tray = trayIcon trayIcon.show()
在 silnik 文件夹中
创建 mytray.py:

import sys from PySide6.QtWidgets import (QSystemTrayIcon, QMenu) from PySide6.QtCore import (QCoreApplication) class SystemTrayIcon(QSystemTrayIcon): def __init__(self, icon): super().__init__() self.setIcon(icon) self.menu = QMenu() self.exitAction = self.menu.addAction("Wyjście") self.setContextMenu(self.menu) self.exitAction.triggered.connect(self.exit) def exit(self): QCoreApplication.exit()
    

0
投票
它可以更容易

相反:

QtWidgets.QSystemTrayIcon.__init__(self, icon, parent)
写:

super().__init__(self, icon, parent)
    

0
投票
你好,我测试了这种方式,这种方式适用于 PyQt6 你应该在你的代码中写下

self 这非常重要。那么你的代码就是为了那个self而工作的。如果你不写 self,也许你的程序开始崩溃。

我的代码:

从 PyQt6.QtWidgets 导入 * 从 PyQt6.QtGui 导入 * 来自 PyQt6.QtCore 导入 *

tray tab_context_menu= QMenu() #为系统创建菜单tray_context_menu.addAction("First Action") 托盘_context_menu.addSeparator()托盘_context_menu.addAction(“第二个 行动”)

self.my_tray = QSystemTrayIcon(self) #创建系统托盘self.my_tray.setIcon(QIcon("my_icon.png")) self.my_tray.setToolTip("工具提示") self.my_tray.setContextMenu(tray_context_menu) self.my_tray.setVisible(True) # 显示 self.my_tray.show() # 显示

self.my_tray.showMessage("我的标题", "欢迎来到我的程序") #也可以显示消息#这条消息的图标是“信息” 图标”,显示时间为10秒。您还可以设置图标和时间。

self.my_tray.activated.connect(self.onTrayIconActivated)#也可以获取是否激活

def onTrayIconActivated(自我,原因): 如果原因== QtGui.QSystemTrayIcon.Trigger: print(">>> 单击了系统托盘图标")

if reason == QtGui.QSystemTrayIcon.DoubleClick: print(">>> system tray icon double clicked")

© www.soinside.com 2019 - 2024. All rights reserved.