(I comenzó con la respuesta de Andy, así que gracias a Andy!)
1) aboutToHide() funciona, volviendo a hacer estallar el menú en una posición en caché, pero también puede entrar en un bucle infinito. Probar si hacer clic en el mouse fuera del menú para ignorar la reapertura debería ser el truco.
2) Probé un filtro de eventos pero bloquea el clic real al elemento del menú.
3) Use ambos.
Aquí hay un patrón sucio para demostrar que funciona. Esto mantiene a la intemperie menú cuando el usuario mantiene pulsada la tecla CTRL al hacer clic en:
# in __init__ ...
self.options_button.installEventFilter(self)
self.options_menu.installEventFilter(self)
self.options_menu.aboutToHide.connect(self.onAboutToHideOptionsMenu)
self.__options_menu_pos_cache = None
self.__options_menu_open = False
def onAboutToHideOptionsMenu(self):
if self.__options_menu_open: # Option + avoid an infinite loop
self.__options_menu_open = False # Turn it off to "reset"
self.options_menu.popup(self.__options_menu_pos_cache)
def eventFilter(self, obj, event):
if event.type() == QtCore.QEvent.MouseButtonRelease:
if obj is self.options_menu:
if event.modifiers() == QtCore.Qt.ControlModifier:
self.__options_menu_open = True
return False
self.__options_menu_pos_cache = event.globalPos()
self.options_menu.popup(event.globalPos())
return True
return False
Yo digo que es sucia porque el widget aquí está actuando como un filtro de eventos, tanto para el botón que abre el menú, así como el propio menú . Usar clases de filtros de eventos explícitos sería lo suficientemente fácil de agregar y facilitaría un poco las cosas.
Los bools probablemente podrían reemplazarse con una comprobación para ver si el mouse está sobre el menú, y si no, no lo abra. Sin embargo, la clave CTRL todavía debe tenerse en cuenta para mi caso de uso, por lo que probablemente no esté lejos de ser una buena solución.
Cuando el usuario mantiene presionada la tecla CTRL y hace clic en el menú, activa un interruptor para que el menú se abra nuevamente cuando intenta cerrarse. La posición se almacena en caché para que se abra en la misma posición. Hay un parpadeo rápido, pero se siente bien ya que el usuario sabe que está presionando una tecla para que esto funcione.
Al final del día (literalmente) ya tenía todo el menú haciendo lo correcto. Solo quería agregar esta funcionalidad y definitivamente no quería cambiar a usar un widget solo para esto. Por esta razón, estoy manteniendo incluso este sucio parche por ahora.
Muchas gracias. Con el estilo plastique hay un margen para agregar. Así que puse la casilla de verificación en un widget con un diseño, y lo establecí en los márgenes (tal vez hay una manera más simple ...) Una última cosa: la casilla de verificación no se expande a todo el ancho del menú, por lo que si ocurre después del final de la etiqueta de la caja, el menú está cerrado y el cuadro no está marcado. Establecer la política de tamaño no tiene ningún efecto. – gregseth
Esto no funciona con 'QsystemTrayIcon.contextMenu()' en Ubuntu Unity ya que Unity no muestra Widgets desde adentro 'QWidgetAction' – Germar
@gregseth ¿Hay alguna manera de expandir la casilla de verificación al ancho completo del menú? – bob