Opened 3 years ago
Closed 3 years ago
#9068 closed defect (fixed)
qtconsole receives QContextMenuEvents when volume data context menu used
| Reported by: | Zach Pearson | Owned by: | Tom Goddard |
|---|---|---|---|
| Priority: | low | Milestone: | |
| Component: | UI | Version: | |
| Keywords: | Cc: | Eric Pettersen | |
| Blocked By: | Blocking: | ||
| Notify when closed: | Platform: | all | |
| Project: | ChimeraX |
Description
To reproduce:
Open one of the RIDER Lung CTs (I used series 8), right click the volume menu, enable the bounding box, then try to launch the shell from the command line with "ui tool show shell<enter>" -- this can either be a remembered command or one you typed.
Does not reproduce when using the ribbon to turn on the bounding box, or the Tool menu to launch the shell.
Change History (8)
comment:1 by , 3 years ago
| Cc: | added |
|---|---|
| Owner: | set to |
| Status: | new → assigned |
| Summary: | qtconsole receives QContextMenuEvents when bounding box enabled → qtconsole receives QContextMenuEvents when volume data context menu used |
comment:2 by , 3 years ago
It is useful to include the error in a bug report. Mousing over the shell after using the Volume Viewer histogram context menu produces a stream of this traceback.
Traceback (most recent call last):
File "/Users/goddard/ucsf/chimerax/ChimeraX.app/Contents/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/qtconsole/console_widget.py", line 482, in eventFilter
pos = event.globalPosition().toPoint()
AttributeError: 'QContextMenuEvent' object has no attribute 'globalPosition'
AttributeError: 'QContextMenuEvent' object has no attribute 'globalPosition'
File "/Users/goddard/ucsf/chimerax/ChimeraX.app/Contents/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/qtconsole/console_widget.py", line 482, in eventFilter
pos = event.globalPosition().toPoint()
comment:3 by , 3 years ago
This seems like a Qt or PyQt bug. The qtconsole shell code gets a QContextMenuEvent e that has e.type() == QEvent.MouseMove. Such an event is supposed to have e.type() == QEvent.ContextMenu. Every mouse move in the shell window triggers this error.
To generate the error it only requires posting the Volume Viewer histogram context menu, and then clicking outside the menu to dismiss it. It does not require clicking any menu entry.
The volume viewer code that creates the menu creates callbacks which reference the event that posted the memory. I changed the code so it does not keep any reference to the posting event and then the error does not happen when the menu is simply posted. But it still happens when the "Show outline box" menu entry is clicked!
I changed posting the menu so it uses the same call (ui.post_context_menu()) used by all our Tool context menus. That made no difference. That code cast menu.exec() which starts some event subloop processing that does not return until the menu is unposted.
Commenting out the callback (action.triggered.connect(cb)) line for the 4 volume menu entries avoids the problem even if the menu entries are used. Or if I still connect the callbacks but have then simply return, there is no problem. If I put a try/except around the callbacks so they raise no error I still get the problem.
Commenting out just the logging of the command in the show outline box menu callback avoids the error.
It could be a reference count problem. I tried keeping the QActions alive and the callbacks, still get the error.
The histogram has its own context menu. If I instead make it the tool context menu get the same problem.
I'm baffled. The other tool context menus tend to do simpler things in their callbacks. On the other hand, it doesn't even require clicking any of the menu entries in the original code if the callbacks simply hold onto a reference to the post event. The same error occurs even if the callbacks are never called!
comment:4 by , 3 years ago
This bug happens in ChimeraX 1.6.1 on Mac. It only requires posting the Volume Viewer histogram context menu, then clicking outside the menu to dismiss it, then click in the shell window. If I simply comment out registering the menu entry callbacks (line action.trigger.connect(cb)), then the error no longer happens. So even though the callbacks are never called, merely registering them leads to the error. This suggests it is an object lifetime problem. The callbacks do hold a reference to the posting QEvent instance and tests show that alone will cause this error. That seems like a PyQt bug that holding a reference to the posting event would cause later errors in the shell.
comment:5 by , 3 years ago
My best guess is that this PyQt/Qt bug happens when the posting QEvent is kept alive too long. There is no call to delete a QEvent in Qt. (QEvent.accept() did not fix anything.) It seems that even the somewhat more complicated callbacks of the volume histogram code which might generate more Qt events somehow keep the event alive triggering the bug. Maybe setting the event = None before posting the menu would delete it and avoid the bug. Yes, that worked.
ChimeraX 1.5 and 1.4 have the same bug. ChimeraX 1.3 which used Qt 5 does not have the bug.
comment:6 by , 3 years ago
Seems not too hard to work around though. Three of the callbacks hold a reference to the event. One doesn't even use it. The other two could be passed the event's xy coordinates instead of the event instance itself.
comment:7 by , 3 years ago
I made your suggested change at the start of my debugging and it does not solve the problem. But doing that and setting "event = None" before posting the menu so the code does not hold onto any reference to the event at the time the menu gets posted works around it. So that is what I am going with. Already wasted 3 hours. I am not a fan of Qt/PyQt.
comment:8 by , 3 years ago
| Resolution: | → fixed |
|---|---|
| Status: | assigned → closed |
Fixed.
Worked around the Qt/PyQt bug by removing all references to the posting QEvent instance before posting the menu.
This happens only when using the context menu obtained by right-clicking over the volume histogram (including simply dismissing that menu by clicking outside it), followed by bringing up the Python shell by any means. It does not happen by using the normal context menu for a tool (including Volume Viewer's own "normal" context menu), so whatever code produces the volume-data context menu somehow causes this. Perhaps that code needs to use session.ui.post_context_menu()?