canvases, zooming widgets, printing, and timelines

Sorry if this sounds like a whine or a rant. It really isn't.

I continue to be amazed by the wxpython. In ways it is incredibly elegant and powerful. In other ways it is quite poorly thought out.

Here's my current beef. I spent much of the 1990s being a NeXTSTEP programmer. NeXTSTEP is now called Cocoa and it's the basis of the Mac OS X GUI. But I can't use NeXTSTEP because I want my code to run on Linux.

With NeXTSTEP, printing is pretty easy. You just send a message to your object and it prints. Or it makes PDF or PS code that can be saved away. Simple.

After about an hour of work I got printing under wxwidgets to work. I'm amazed that you can't just send a print() message to the Frame class and have the Frame print. The underlying design problem seems to be that EVT_PAINT doesn't send the DC that you are supposed to paint into, so the code that handles the event is separated from the code that actually does the painting. As a result, you need to have different code paths for printing and painting, which then get combined in a lower-level function. My Time Panel does it like this:

class TimePanel(wx.Panel):
     def __init__(self, parent):
         wx.Panel.__init__(self, parent, -1)
         self.SetBackgroundColour(wx.WHITE)
  ... blah blah blah ...

     def Paint(self,dc):
  """ Just a dummy paint method """
         dc.Clear()
         foreground = wx.NamedColour("red")
         background = wx.NamedColour("white")
         dc.DrawTextList(["Hi Sonia"],[(100,100)],[foreground],[background])

     def OnPaint(self, evt):
         dc = wx.PaintDC(self)
         self.Paint(dc)

So my wx.Printout subclass calls theframe.Paint( self.GetDC()). It's a mess, but at least I can try to hide some of the mess.

My questions:

1. The wxpython demo printing example has something called a canvas, but the canvas just seems to be a frame that implements these three methods:

     def getWidth(self):
  ... blah ...

     def getHeight(self):
  ... blah ...

     def DoDrawing(self,dc,ignore):
         self.Paint(dc)

I see that wxpython has support for a wx.lib.flatcanvas by Chris Barker (chris.barker@noaa.gov) and for a glcanvas (which doesn't work on my system because I don't have OpenGL installed). floatcanvas looks like a great start, but I'm hadpressed to find some decent examples. Should I use it?

2. I'd like to drop the float canvas into a scrolling view that supports zoom and mouse events. Again, the wxPython demo seems to have the start of a system, but it's really big and intermixes the code that makes the canvas with the code that makes the demo. Do we have anything clean?

Is this an area that people care about?

3. I'm actually interested in some graphical depictions of timelines. Is there anything pre-packaged ready to go?

Thanks.

Simson

Simson Garfinkel wrote:

Sorry if this sounds like a whine or a rant. It really isn't.

I continue to be amazed by the wxpython. In ways it is incredibly elegant and powerful. In other ways it is quite poorly thought out.

Here's my current beef. I spent much of the 1990s being a NeXTSTEP programmer. NeXTSTEP is now called Cocoa and it's the basis of the Mac OS X GUI. But I can't use NeXTSTEP because I want my code to run on Linux.

With NeXTSTEP, printing is pretty easy. You just send a message to your object and it prints. Or it makes PDF or PS code that can be saved away. Simple.

After about an hour of work I got printing under wxwidgets to work. I'm amazed that you can't just send a print() message to the Frame class and have the Frame print. The underlying design problem seems to be that EVT_PAINT doesn't send the DC that you are supposed to paint into, so the code that handles the event is separated from the code that actually does the painting. As a result, you need to have different code paths for printing and painting, which then get combined in a lower-level function. My Time Panel does it like this:

class TimePanel(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent, -1)
        self.SetBackgroundColour(wx.WHITE)
    ... blah blah blah ...

    def Paint(self,dc):
    """ Just a dummy paint method """
        dc.Clear()
        foreground = wx.NamedColour("red")
        background = wx.NamedColour("white")
        dc.DrawTextList(["Hi Sonia"],[(100,100)],[foreground],[background])

    def OnPaint(self, evt):
        dc = wx.PaintDC(self)
        self.Paint(dc)

If you're trying to get a screenshot of your application, I usually use this method (suggested by Andrea Gavana) to get a :

Here's my slightly modified version:

<code>

def TakeScreenShot(self):
    """ Takes a screenshot of the screen at give pos & size (rect). """
    print 'Taking screenshot...'
    rect = self.frame.GetRect()
    # see ActiveState Community - Boosting coder and team productivity with ready-to-use open source languages and tools.
    # created by Andrea Gavana

    #Create a DC for the whole screen area
    dcScreen = wx.ScreenDC()

    #Create a Bitmap that will hold the screenshot image later on
    #Note that the Bitmap must have a size big enough to hold the screenshot
    #-1 means using the current default colour depth
    bmp = wx.EmptyBitmap(rect.width, rect.height)

    #Create a memory DC that will be used for actually taking the screenshot
    memDC = wx.MemoryDC()

    #Tell the memory DC to use our Bitmap
    #all drawing action on the memory DC will go to the Bitmap now
    memDC.SelectObject(bmp)

    #Blit (in this case copy) the actual screen on the memory DC
    #and thus the Bitmap
    memDC.Blit( 0, #Copy to this X coordinate
        0, #Copy to this Y coordinate
        rect.width, #Copy this width
        rect.height, #Copy this height
        dcScreen, #From where do we copy?
        rect.x, #What's the X offset in the original DC?
        rect.y #What's the Y offset in the original DC?
        )

    #Select the Bitmap out of the memory DC by selecting a new
    #uninitialized Bitmap
    memDC.SelectObject(wx.NullBitmap)

    img = bmp.ConvertToImage()
    fileName = "myImage.png"
    img.SaveFile(fileName, wx.BITMAP_TYPE_PNG)
    print '...saving as png!'

</code>

Then I use HtmlEasyPrinting to stick it in what amounts to an HTML page that I can print it. I can't comment on FloatCanvas, but they have their own mailing list and Chris and another guy or two are quite active at helping users with it. I think the lack of docs is a major sticking point though.

So my wx.Printout subclass calls theframe.Paint( self.GetDC()). It's a mess, but at least I can try to hide some of the mess.

My questions:

1. The wxpython demo printing example has something called a canvas, but the canvas just seems to be a frame that implements these three methods:

    def getWidth(self):
    ... blah ...

    def getHeight(self):
    ... blah ...

    def DoDrawing(self,dc,ignore):
        self.Paint(dc)

I see that wxpython has support for a wx.lib.flatcanvas by Chris Barker (chris.barker@noaa.gov) and for a glcanvas (which doesn't work on my system because I don't have OpenGL installed). floatcanvas looks like a great start, but I'm hadpressed to find some decent examples. Should I use it?

2. I'd like to drop the float canvas into a scrolling view that supports zoom and mouse events. Again, the wxPython demo seems to have the start of a system, but it's really big and intermixes the code that makes the canvas with the code that makes the demo. Do we have anything clean?

In most cases you can just copy and paste the code out of the demo and remove the references to the logging to the demo and a little bit of tweaking. See here: Using wxPython Demo Code - wxPyWiki

For this particular demo, I just copied and pasted the code right out and added "import wx" to the top and ran it. The only hiccup was that it needed numpy and once I had that, the demo ran. I have included it as an attachment. I'm guessing their is additional demo code in the download for FloatCanvas from Chris's site as well.

Is this an area that people care about?

3. I'm actually interested in some graphical depictions of timelines. Is there anything pre-packaged ready to go?

Thanks.

Simson

I don't know if there is or not. Give your Google-Fu a try...

FloatCanvasDemo.py (83.6 KB)

···

-------------------
Mike Driscoll

Blog: http://blog.pythonlibrary.org
Python Extension Building Network: http://www.pythonlibrary.org

Simson Garfinkel wrote:

Here's my current beef. I spent much of the 1990s being a NeXTSTEP programmer. NeXTSTEP is now called Cocoa and it's the basis of the Mac OS X GUI. But I can't use NeXTSTEP because I want my code to run on Linux.

Have you checked out GnuStep? Maybe not robust enough, but it's there.

With NeXTSTEP, printing is pretty easy. You just send a message to your object and it prints. Or it makes PDF or PS code that can be saved away. Simple.

I think NeXTSTEP is built, from the core, on top of displayPS (and now DisplayPDF). Which is a nice design decision, as it makes this kind of thing easy.

After about an hour of work I got printing under wxwidgets to work. I'm amazed that you can't just send a print() message to the Frame class and have the Frame print.

wxWidgets, on the other hand, is built on top of a number of native toolkits, and let's them draw their own widgets, so there is no one drawing API to make this easy.

So my wx.Printout subclass calls theframe.Paint( self.GetDC()). It's a mess, but at least I can try to hide some of the mess.

this is the conventional way to do it. I don't think it's such a mess though, is seems clean to me. However, drawing is, in general, more complicated than it could/should be. Depending on your needs, you may want to check out one of the higher level drawing canvases:

system because I don't have OpenGL installed). floatcanvas looks like a great start, but I'm hadpressed to find some decent examples. Should I use it?

That depends on your needs. What are you trying to do?

2. I'd like to drop the float canvas into a scrolling view that supports zoom and mouse events. Again, the wxPython demo seems to have the start of a system, but it's really big and intermixes the code that makes the canvas with the code that makes the demo. Do we have anything clean?

There are a bunch more examples in the FloatCanvas SVN:

http://svn.wxwidgets.org/viewvc/wx/wxPython/3rdParty/FloatCanvas/Demos

Those are all small, self contained apps.

Though the demo and the canvas aren't intermixed -- FloatCanvas itself is in wx.lib.floatcanvas

There are now two FloatCanvas -- there is a new version, started with funding from Google Summer of Code:

http://svn.wxwidgets.org/viewvc/wx/wxPython/3rdParty/branches/FloatCanvas/SOC2008_FloatCanvas/

The new version has a greater levels of abstraction that make it more powerful and flexible, but it also less mature, and I"m not sure it's rendering right on GTK at this point.

Please join us on the floatcanvas mailing list for more detail:

http://mail.mithis.com/cgi-bin/mailman/listinfo/floatcanvas

3. I'm actually interested in some graphical depictions of timelines. Is there anything pre-packaged ready to go?

I don't think so, though someone was working on something similar a little while back -- you might check the archives of this list.

Look for posts by Stephanie Lück

-Chris

···

--
Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov