Hi there
This post is related to the open issue of Phoenix MouseWheelEvent is broken if MotionEvent is saved, where OP pointed out that there are similar bugs with matplotlib/WXAgg. I have already opened the issue in [Matplotlib issue tracker] and shown options for resolving it, but a few things are not clear to me.
This issue is caused by keeping a reference to the event object.
Hereās an example with a bit of modification of the original code from the [Phoenix issue tracker] that reproduces the problem.
Code Example (click to expand)
import sys
import wx
print('sys.version:', sys.version)
print('wx.__version__:', wx.__version__)
class MyFrame(wx.Frame):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.Bind(wx.EVT_MOTION, self.OnMouseMove)
self.Bind(wx.EVT_MOUSEWHEEL, self.OnMouseWheel)
self.last_event = None
def OnMouseMove(self, evt):
if evt.leftIsDown:
print("Saving MouseMove event")
self.last_event = evt
def OnMouseWheel(self, evt):
print("Wheel rotation: " + str(evt.GetWheelRotation()))
test(self.last_event)
def test(obj):
d = {}
for key in dir(obj):
try:
print("key =", key)
d[key] = getattr(obj, key) # Windows fatal exception: access violation
except Exception as e:
print(e)
pass
return d
app = wx.App(0)
frame = MyFrame(None)
frame.Show()
app.MainLoop()
To reproduce the bug and messages
- Launch this script with debug options
$ python -Xdev -Xtracemalloc āscript.pyā - Press LBtn and move the mouse.
Then, the lastwx.MouseEvent
object is saved. - Scroll the mouse wheel to show outputs.
Then, a fault occurs when accessingevt.ClassInfo
, and it crashes withWindows fatal exception: access violation
.
I confirmed this for Windows 10 64 bit &
PY38 - wx 4.0.7 and wx 4.1.1,
PY39 - wx 4.1.1.
In my understanding, the reference of the event object should not be kept outside the event chain.
Therefore, the statement such as self.last_event = evt
should be avoided. Otherwise, it will refer to the dead c++ object, and the program will crash easily. If you need event information, you need to save them as primitve types such as int, float, etc.
To avoid this, you can change it as follows.
- self.last_event = evt
+ self.last_event = evt.__class__(evt)
This calls the implicit copy constructor, but itās tricky and undocumented. Iām not sure it will work in future versions.
So, my questions are,
- Is this issue likely to be improved in a future version?
- Or should it be stated in
wx.Event
doc? - Can the above ātrickyā method be used in future versions?
Kind Regards