Pre-select QMenu item

Maurizio Berti maurizio.berti at gmail.com
Mon Mar 4 03:48:51 GMT 2024


That may depend on many aspects.

First of all, keep in mind that the QMenu implementation is quite complex,
as it needs to consider lots of aspects, including the size hint (including
that of each item, which may even recursively ask for the current size hint
of the whole menu), the position relative to the screen (and, therefore,
the screen it would eventually be shown), not to mention OS limitations,
including screen size capabilities which would eventually cause scrolling
or further menu columns, making event management even more complex. There's
a lot of things going on before a menu is finally shown, and some of them
may work unexpectedly under certain conditions.

Then, setActiveAction() only sets the *highlighted* action at an arbitrary
moment, and that may even change depending on platform aspects and their
event management. Remember that context menus may be triggered differently
depending on the OS: normally, on *nix it happens when the mouse button (or
context menu key) is pressed, on Windows when it's released.
Things could also become even uglier when a QMenu has just been created
(I'm not completely sure, but calling ensurePolished() before doing
anything else *may* help, especially if you're using a custom style/proxy
or stylesheets, but parent/child relation may also come into play).

If you want to ensure that an item is highlighted, from the UX perspective,
you should also ensure that that item is actually placed under the mouse
(assuming that the menu is being shown after a ContextMenu event)
using popup(pos,
action) (see the docs <https://doc.qt.io/qt-5/qmenu.html#popup>), so that
the user *does* know, intuitively, that the current item is the default
selected one, as long as the menu geometry doesn't go beyond the current
QScreen geometry.

This is also important for actions used for sub menus: QMenu automatically
clears any active action whenever a further mouse event happens after
showing, which brings back to what mentioned above: you need to be aware
about what event triggers the popup, and also when/how it does that. Do
further testing, as it's possible that you only made assumptions ignoring
the difference between press and release events: the simple solution is to
try to trigger the menu by pressing the mouse button and wait, *then*
release that button.

Setting the "atAction" with popup() may not be appropriate, though, for
instance when using QAbstractButton's menus. If that's the case, you may
consider using possible work arounds, including "bad ones" (such as a
singleShot QTimer) that delay the setActiveAction call, which can still be
undone based on the aspect explained above: for instance, if moving the
mouse right after that.

That said, I know it can be difficult to provide the actual reproducible
code in large contexts, but that often means that you're possibly doing
something wrong somewhere else, or that you're not calling the related
functions properly (or in the proper order).
I strongly suggest you to put more efforts and try to create a reproducible
example: with any luck, you'll be able to find out the issue on your own,
otherwise we'll have more ways to understand where the problem is and
eventually help you. Knowing more about your environment (PyQt/Qt versions,
OS, and WM if using Linux) would certainly help. Note that if you're on
Linux, such things easily become a nightmare to deal with. Most of the
times, it's really not worth it.

Best regards,
MaurizioB

Il giorno dom 3 mar 2024 alle ore 01:22 John F Sturtz <john at sturtz.org> ha
scritto:

> Hello good folks.
>
> I think this is a relatively straightforward question.  But the issue is
> complicated by the fact that what I am trying to do works perfectly well
> (seemingly) in my small test program.  In my larger app, not so much.
>
> I am creating a QMenu object on the fly and then using .exec() to display
> it as a popup.  What I would like to do is cause the first item in the menu
> to be already selected when it pops up.
>
> I'd have thought this would be simple enough to accomplish, using
> .setActiveAction().  And indeed, in the small test program I wrote (which
> is in the zip file attached), it does seem to work as I expect.  The
> pertinent code is:
>
>             menu = QtWidgets.QMenu()
>             for s in ('Foo', 'Bar', 'Baz'):
>                 menu.addAction(QtGui.QIcon('account.png'), s)
>             menu.setActiveAction(menu.actions()[0])
>             menu.exec(self.mapToGlobal(QtCore.QPoint(20, 20)))
>
> In my smaller test program, this does just what I expect:  When the menu
> pops up, the first item is selected.
>
> Here's the rub:  When I put essentially the exact same code into my larger
> app, it behaves oddly.  The first time I display the popup menu, it
> doesn't work.  The popup menu displays, but it does not select the first
> item as I would expect.  The next time I display the popup, it does
> work.  And every time thereafter, until the app shuts down.
>
> I realize this is a bit of a slippery question, because I can't post the
> code that doesn't work -- only the code that does.  Apparently, something
> that is going on with the larger app is messing with this.  But I'm
> wondering if anyone has any ideas as to why this might be the case, or what
> I might try to get around it.
>
> Thanks!
>
> /John
>


-- 
È difficile avere una convinzione precisa quando si parla delle ragioni del
cuore. - "Sostiene Pereira", Antonio Tabucchi
http://www.jidesk.net
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.riverbankcomputing.com/pipermail/pyqt/attachments/20240304/713f4065/attachment-0001.htm>


More information about the PyQt mailing list