You need to enable JavaScript to run this app. 使用qasync与aiohttp时QSystemTrayIcon无法显示,求可行解决方案
优惠活动
大模型
产品
解决方案
定价
更多

使用qasync与aiohttp时QSystemTrayIcon无法显示,求可行解决方案

问题根因
  • web.run_app()是aiohttp的阻塞式启动方法,调用后会独占当前线程,后续Qt的界面事件循环完全没有运行机会,因此系统托盘图标不会被渲染显示。
  • 你已经初始化了qasync.QEventLoop但没有显式启动该事件循环,程序执行到trayIcon.startServer()后就直接阻塞,后续逻辑全部无法执行。
  • 额外注意:部分桌面环境要求QSystemTrayIcon必须显式设置图标才会显示,未设置图标时也可能出现托盘不显示的问题。
修复步骤
  1. 替换阻塞的web.run_app调用,改用aiohttp的非阻塞API手动启动服务,共用qasync的事件循环。
  2. 显式启动qasync的事件循环,将aiohttp服务启动逻辑作为协程提交到事件循环中运行。
  3. 为QSystemTrayIcon显式设置图标,兼容不同桌面环境的显示要求。
完整修复后代码
import asyncio
import sys
import datetime
from functools import cached_property

from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import QIcon

import qasync
from aiohttp import web


class TrojanGUI(QSystemTrayIcon):
    def __init__(self, parent=None, **kwargs):
        super().__init__(parent, **kwargs)
        # 显式设置托盘图标,这里用Qt内置图标,可替换为自定义图标路径
        self.setIcon(QApplication.style().standardIcon(QStyle.SP_ComputerIcon))
        self.setup_server()
        # 可选:添加右键菜单方便退出程序
        menu = QMenu()
        exit_action = menu.addAction("退出")
        exit_action.triggered.connect(QApplication.quit)
        self.setContextMenu(menu)

    def setup_server(self):
        self.app.add_routes([web.get("/proxy.pac", self.hello)])

    @cached_property
    def app(self):
        return web.Application()

    async def hello(self, request):
        print(datetime.datetime.now().strftime("%H:%M:%S"))
        # 这里为示例pac内容,可替换为你的实际逻辑
        self.pacContent = "function FindProxyForURL(url, host) { return 'PROXY 127.0.0.1:8080'; }"
        return web.Response(text=self.pacContent)

    # 改为异步非阻塞启动方法
    async def startServer(self):
        runner = web.AppRunner(self.app)
        await runner.setup()
        site = web.TCPSite(runner, port=23336)
        await site.start()
        print("服务已启动,监听端口23336")
        # 保持服务持续运行
        while True:
            await asyncio.sleep(3600)


def main():
    QApplication.setQuitOnLastWindowClosed(False)

    app = QApplication(sys.argv)
    loop = qasync.QEventLoop(app)
    asyncio.set_event_loop(loop)

    trayIcon = TrojanGUI()
    trayIcon.show()

    # 整合服务启动和Qt事件循环运行
    with loop:
        loop.create_task(trayIcon.startServer())
        loop.run_forever()


if __name__ == "__main__":
    main()

内容的提问来源于stack exchange,提问作者iMath

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.13 07:39:03