模拟用户在QSystemTrayIcon中的点击

1 投票
1 回答
602 浏览
提问于 2025-04-18 04:00

即使activated这个槽函数正在执行,菜单还是没有显示出来。我手动点击了托盘图标,并模拟了点击,发现它们走的执行逻辑是一样的。

目前我有

class MyClass(QObject):
   def __init__():
       self._testSignal.connect(self._test_show)
       self.myTrayIcon.activated.connect(lambda reason: self._update_menu_and_show(reason))

   def show():
       self._testSignal.emit()

   @pyqtSlot()
   def _test_show():
       self._trayIcon.activated.emit(QtWidgets.QSystemTrayIcon.Trigger)

   @QtCore.pyqtSlot()
   def _update_menu_and_show(reason):
       if reason in (QtWidgets.QSystemTrayIcon.Trigger):
        mySystemTrayIcon._update_menu()

...
class MySystemTrayIcon(QSystemTrayIcon):

   def _update_menu(self):
      # logic to populate menu
      self.setContextMenu(menu)
...
MyClass().show()

1 个回答

1

这是我让托盘图标关联的上下文菜单弹出的方式

class MyClass(QObject):
   def __init__():
       self._testSignal.connect(self._test_show)
       self.myTrayIcon.activated.connect(lambda reason: self._update_menu_and_show(reason))

   def show():
       self._testSignal.emit()

   @pyqtSlot()
   def _test_show():
       self._trayIcon.activated.emit(QSystemTrayIcon.Context)

   @QtCore.pyqtSlot()
   def _update_menu_and_show(reason):
       if reason in (QSystemTrayIcon.Trigger, QSystemTrayIcon.Context):
           mySystemTrayIcon._update_menu()
           # Trigger means user initiated, Context used for simulated
           # if simulated seems like we have to tell the window to explicitly show

           if reason == QSystemTrayIcon.Context:
               mySystemTrayIcon.contextMenu().setWindowFlags(QtCore.Qt.WindowStaysOnTopHint|QtCore.Qt.FramelessWindowHint)
               pos = mySystemTrayIcon.geometry().bottomLeft()
               mySystemTrayIcon.contextMenu().move(pos)
               mySystemTrayIcon.contextMenu().show()

...
class MySystemTrayIcon(QSystemTrayIcon):

   def _update_menu(self):
      # logic to populate menu
      self.setContextMenu(menu)
...
MyClass().show()

看起来你需要在上下文菜单上设置 WindowStaysOnTopHint,这样它才能显示出来。这个方法是针对Mac系统的,因为它假设任务栏是在顶部的。

一个副作用是,这个上下文菜单总是会在最上面,即使用户点击了其他地方。我在上下文菜单上放了一个事件过滤器,唯一有用的事件是 QEvent.Leave

撰写回答