From: Michael S. <mic...@as...> - 2005-01-19 01:24:44
|
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(2*pi*t) 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() |