The (new) navigation toolbar under WXAgg

Hi!

A few weeks ago I started using Python, Matplotlib,
and WxPython for a new project, and continue to be quite impressed. I now ran
into a problem however, which I cannot solve in a decent way: I am using a slightly
more complicated GUI than the ones in the examples, and positioned a Matplotlib
canvas and the toolbar inside a sizer, which is not the “root”-most
sizer (in the init constructor of my wx.Frame-derived class I call “self.SetSizer(sizer_A)”
while I add the Matplotlib canvas to a different sizer_B, kind of like “self.sizer_B.Add(self.canvas,
1, wxTOP | wxLEFT | wxEXPAND)”, with sizer_B being added via intermediate
objects to sizer_A).

What now happens isn’t completely clear to me –
but it looks as if the events aren’t handled correctly anymore (nothing at
all happens, if I use the custom sizing given in one of the examples; if I call
self.SetToolBar(self.toolbar) instead, some of the buttons work, I think). If I
position both the canvas and the toolbar in the “root”-most sizer
instead, everything runs fine. Does anyone know a way to solve this?

I am using WxGlade to write some of the GUI code,
because it seems to save some typing work. Below, I added a simple example of
the problem I encounter. I basically combined the “embedding_in_wx4.py”
with some WxGlade-created code (the frame contains a sizer_A with a button and
a sizer_2 which contains the sizer_B that in turn contains the canvas. Of
course, this setup would be possible without this structure, it is just meant to
illustrate…)

Does someone also have some input on WxGlade or
other choices that are out there? What about Boa Constructor? Is that any good?
Currently I am using SPE…

Thanks a lot in advance for your help,

Michael Sielemann

______ example code (not working like this, to
illustrate the problem I am encountering ________________

#!/usr/bin/env python

-- coding: ISO-8859-1 --

generated by wxGlade 0.3.5.1 on Tue Jan 18

17:42:12 2005

from matplotlib.numerix import arange, sin, pi

import matplotlib

uncomment the following to use wx rather than

wxagg

#matplotlib.use(‘WX’)

#from matplotlib.backends.backend_wx import
FigureCanvasWx as FigureCanvas

comment out the following to use wx rather than

wxagg

matplotlib.use(‘WXAgg’)

from matplotlib.backends.backend_wxagg import
FigureCanvasWxAgg as FigureCanvas

from matplotlib.backends.backend_wx import
NavigationToolbar2Wx

from matplotlib.backends.backend_wx import
_load_bitmap

from matplotlib.figure import Figure

from matplotlib.numerix import rand

import wx

class MyNavigationToolbar(NavigationToolbar2Wx):

"""

Extend the default wx toolbar

with your own event handlers

"""

ON_CUSTOM = wx.NewId()

def __init__(self, canvas,

cankill):

NavigationToolbar2Wx.init(self, canvas)

    # for

simplicity I’m going to reuse a bitmap from wx, you’ll

···
    #

probably want to add your own.

self.AddSimpleTool(self.ON_CUSTOM, _load_bitmap(‘stock_left.xpm’),

‘Click me’, ‘Activate custom contol’)

EVT_TOOL(self, self.ON_CUSTOM, self._on_custom)

def _on_custom(self, evt):

    # add

some text to the axes in a random location in axes (0,1)

    # coords)

with a random color

    # get the

axes

    ax =

self.canvas.figure.axes[0]

    #

generate a random location can color

    x,y =

tuple(rand(2))

    rgb =

tuple(rand(3))

    # add the

text and draw

ax.text(x, y, ‘You clicked me’,

transform=ax.transAxes,

color=rgb)

self.canvas.draw()

evt.Skip()

class MyFrame(wx.Frame):

def __init__(self, *args,

**kwds):

    # begin

wxGlade: MyFrame.init

kwds[“style”] = wx.DEFAULT_FRAME_STYLE

wx.Frame.init(self, *args, **kwds)

self.panel_1 = wx.Panel(self, -1)

self.panel_2 = wx.Panel(self.panel_1, -1)

self.button_1 = wx.Button(self.panel_1, -1, “Useless”)

    # moved

downwards

#self.__set_properties()

#self.__do_layout()

    # end

wxGlade

    #

“embedding_in_wx4.py” sample code integration

self.SetBackgroundColour(wxNamedColor(“WHITE”))

self.figure = Figure(figsize=(5,4), dpi=100)

    self.axes

= self.figure.add_subplot(111)

self.canvas = FigureCanvas(self, -1, self.figure)

    t =

arange(0.0,3.0,0.01)

    s =

sin(2pit)

self.axes.plot(t,s)

self.toolbar = MyNavigationToolbar(self.canvas, True)

self.__set_properties()

    self.__do_layout()

    # end of

“embedding_in_wx4.py” sample code integration

def __set_properties(self):

    # begin

wxGlade: MyFrame.__set_properties

self.SetTitle(“frame_1”)

self.SetSize((600, 500))

    # end

wxGlade

    #

“embedding_in_wx4.py” sample code integration

self.toolbar.Realize()

    # end of

“embedding_in_wx4.py” sample code integration

def __do_layout(self):

    # begin

wxGlade: MyFrame.__do_layout

    sizer_A =

wx.BoxSizer(wx.VERTICAL)

    sizer_2 =

wx.BoxSizer(wx.HORIZONTAL)

    # next

lines were modified by hand

self.sizer_B = wxBoxSizer(wxVERTICAL)

self.sizer_B.Add(self.canvas, 1, wxTOP | wxLEFT | wxEXPAND)

sizer_2.Add(self.sizer_B, 2, wxTOP | wxLEFT | wxEXPAND, 0)

sizer_2.Add(self.button_1, 1, wx.EXPAND|wx.FIXED_MINSIZE, 0)

self.panel_1.SetAutoLayout(True)

self.panel_1.SetSizer(sizer_2)

sizer_2.Fit(self.panel_1)

sizer_2.SetSizeHints(self.panel_1)

sizer_A.Add(self.panel_1, 1, wx.EXPAND, 0)

#self.SetAutoLayout(True)

#self.SetSizer(sizer_A)

#self.Layout()

    # end

wxGlade

    #

“embedding_in_wx4.py” sample code integration

    if

wxPlatform == ‘WXMAC’:

Mac platform (OSX 10.3, MacPython) does not seem to cope with

having a toolbar in a sizer. This work-around gets the buttons

back, but at the expense of having the toolbar at the top

self.SetToolBar(self.toolbar)

    else:

On Windows platform, default window size is incorrect, so set

toolbar width to figure width.

tw, th = self.toolbar.GetSizeTuple()

fw, fh = self.canvas.GetSizeTuple()

By adding toolbar in sizer, we are able to put it at the bottom

of the frame - so appearance is closer to GTK version.

As noted above, doesn’t work for Mac.

self.toolbar.SetSize(wxSize(fw, th))

self.sizer_B.Add(self.toolbar, 0, wxLEFT | wxEXPAND)

    # Capture

the paint message what was the use of
this?

#EVT_PAINT(self, self.OnPaint)

    # update

the axes menu on the toolbar

    self.toolbar.update()

#self.SetSizer(self.sizer)

#self.Fit()

    # end of

“embedding_in_wx4.py” sample code integration

self.SetAutoLayout(True)

self.SetSizer(sizer_A)

self.Layout()

end of class MyFrame

class MyAtmosphereApp(wx.App):

def OnInit(self):

wx.InitAllImageHandlers()

    frame_1 =

MyFrame(None, -1, “”)

self.SetTopWindow(frame_1)

frame_1.Show()

    return 1

end of class MyAtmosphereApp

if name == “main”:

import gettext

gettext.install(“AtmosphereApp”) # replace with the appropriate
catalog name

# more of my init stuff

AtmosphereApp =

MyAtmosphereApp(0)

AtmosphereApp.MainLoop()