Nasty mouse event problem with wxPython

Hi Soren,

2010/5/6 Søren Nielsen <soren.skou.nielsen@...287...>:

Thanks Matt,

The wx.ReleaseMouse() event when called before the wx.MessageBox also works
great.

I have a similar problem when I want to make a popup menu after the user has
clicked on a patch (through the pick event) .. it works on Windows but the
popup menu doesn't show on Linux (or only shows in rare occasions) . A
wx.ReleaseMouse() doesn't seem to work here.. I've made a sample script that
shows the problem. It doesn't use the pick event, but the same problem
applies when using the button_press_event. If I want to go through the pick
event then of course the button_release_event workaround doesn't work
either.

Also, clicking the right and left button like crazy to make the popup menu
show on linux can result in the error:

Traceback (most recent call last):
File
"/usr/lib64/python2.6/site-packages/matplotlib/backends/backend_wx.py", line
1218, in _onKeyDown
FigureCanvasBase.key_press_event(self, key, guiEvent=evt)
File "/usr/lib64/python2.6/site-packages/matplotlib/backend_bases.py",
line 1142, in key_press_event
event = KeyEvent(s, self, key, self._lastx, self._lasty,
guiEvent=guiEvent)
File "/usr/lib64/python2.6/site-packages/matplotlib/backend_bases.py",
line 970, in __init__
LocationEvent.__init__(self, name, canvas, x, y, guiEvent=guiEvent)
File "/usr/lib64/python2.6/site-packages/matplotlib/backend_bases.py",
line 813, in __init__
axes_list = [a for a in self.canvas.figure.get_axes() if
a.in_axes(self)]
File "/usr/lib64/python2.6/site-packages/matplotlib/axes.py", line 1538,
in in_axes
return self.patch.contains(mouseevent)[0]
File "/usr/lib64/python2.6/site-packages/matplotlib/patches.py", line 501,
in contains
x, y = self.get_transform().inverted().transform_point(
File "/usr/lib64/python2.6/site-packages/matplotlib/patches.py", line 119,
in get_transform
return self.get_patch_transform() + artist.Artist.get_transform(self)
File "/usr/lib64/python2.6/site-packages/matplotlib/transforms.py", line
1033, in __add__
return composite_transform_factory(self, other)
File "/usr/lib64/python2.6/site-packages/matplotlib/transforms.py", line
2004, in composite_transform_factory
return CompositeAffine2D(a, b)
File "/usr/lib64/python2.6/site-packages/matplotlib/transforms.py", line
1964, in __init__
Affine2DBase.__init__(self)
File "/usr/lib64/python2.6/site-packages/matplotlib/transforms.py", line
1304, in __init__
Transform.__init__(self)
File "/usr/lib64/python2.6/site-packages/matplotlib/transforms.py", line
87, in __init__
self._parents = WeakKeyDictionary()
File "/usr/lib64/python2.6/weakref.py", line 232, in __init__
def remove(k, selfref=ref(self)):
RuntimeError: maximum recursion depth exceeded while calling a Python object

I don't see that error, but perhaps I didn't emulate "click like
crazy" well enough.

I also see that trying to get a Popup Menu on Linux from events
generated by mpl does not reliably display a menu. In my experience,
a work-around is to replace a direct call to
    wx.Popup(menu)
with
    wx.CallAfter(wx.Popup, menu)

I don't know if this is related to the problem described earlier, in
which the wx object containing the FigureCanvasWxAgg needs to call
ReleaseMouse() on Linux but not Windows. As I said earlier, I have
not investigated very thoroughly so am reluctant to jump to any
conclusions about where the problem really lies and what the best
solution is.

An example with a Popup Menu that displays on right- or left-click of
a FigureCanvasWxAgg is below.
Cheers,

--Matt Newville

#!/usr/bin/python
import wx
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg
from matplotlib.figure import Figure

class PlotFrame(wx.Frame):
    def __init__(self, title='Plot Frame', **kwds):
        wx.Frame.__init__(self, None, -1, title=title, **kwds)
        self.panel = wx.Panel(self, -1,size=(600,500))
        self.fig = Figure()
        self.canvas = FigureCanvasWxAgg(self.panel, -1, self.fig)
        self.fig.add_subplot(111)

        self.canvas.mpl_connect('button_press_event',
                                self.onMouseButtonClick)
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.canvas, 1, wx.LEFT |wx.TOP | wx.GROW)
        self.panel.SetSizer(sizer)

        self.SetAutoLayout(True)
        self.Fit()

    def onMouseButtonClick(self, event=None):
        if event is None:
            return
        if event.inaxes:
            menu = wx.Menu()
            if event.button == 1:
                menu.Append(1, 'Left Click: Set as Background file')
                self.Bind(wx.EVT_MENU, self.onSelect1)
            elif event.button == 3:
                menu.Append(1, 'RightClick: Do something else')
                self.Bind(wx.EVT_MENU, self.onSelect2)

            wx.CallAfter(self.PopupMenu, menu)

    def onSelect1(self, event=None):
        print 'select 1'

    def onSelect2(self, event=None):
        print 'select 2'

if __name__ == '__main__':
    app = wx.PySimpleApp()
    frame = PlotFrame(title='Test')
    frame.Show()
    frame.Raise()
    app.MainLoop()