GooCanvas
Intro
I'll be using python and pygoocanvas for code samples to talk about goocanvas today
There is good reference documentaion for goocanvas: http://people.gnome.org/~gianmt/pygoocanvas/
Unfortunately, it can be a bit tough to find code samples and tutorial
What is goocanvas
So what is a goocanvas?
A goocanvas is a 2d composing surface
You can use it to make pretty much any kind of image
It's kind of like an api around a drawing program
So you can have a ton of fun using a goocanvas, because you are pretty much freed from the constraints of a widget library in creating your UI
goocanvas is cairo under the coverse
and is designed to easily integrate into your gtk app
How to add one to your app
So let's add a goocanvas to a pygtk app
Add it just like a normal pygtk widget
#set up the goo canvas self.goo_canvas = goocanvas.Canvas() self.goo_canvas.set_size_request(640, 480) self.goo_canvas.show() Be sure to set the size, otherwise it defaults to 1000,1000, it does not default to the size alloted to it in your window. Handle window resizing to resize your goocanvas as well For example, if your goocanvas is in a VBox, you can do this: rect = self.builder.get_object("vbox2").get_allocation() self.
remember the root item for your goocanvas, you'll need it later often self.root = self.goo_canvas.get_root_item()
The "root" is like the root of an item tree in XML
adding an item in general
So now that we have a goocanvas, we need to add "Items" to it.
Anything that can be added to a goocanvas is an Item. It get's it's capabilities by inheriting from ItemSimple, and by implementing the Item interface.
Let's add an item to the goocanvas to get a look at how it works in general.
We'll start by adding an image.
First, you need to get a gtk.pixbux for your image:
pb = gtk.gdk.pixbuf_new_from_file(path)
Then you calculate where you want the image to show on the goocanvas. You'll need a top and a left to place most items on a goo canvas.
For example, to center the image, I do this:
cont_left, cont_top, cont_right, cont_bottom = self.goo_canvas.get_bounds() img_w = pb.get_width() img_h = pb.get_height() img_left = (cont_right - img_w)/2 img_top = (cont_bottom - img_h)/2 Now I am ready to create the item. Note that I create the Item, but there is nothing like goocanvas.add(item) rather, when you create the item, you set it's parent property. The parent property is the root of the goocanvas This is why I remember the root goocanvas.Image(pixbuf=pb,parent=self.
This basic pattern is how you add all other types of items.
decide where to put the item, and set it's parent property to the root of the goocanvas.
To remove the item from the goocanvas, you don't tell the goocanvas to remove it
rather you tell the item to remove itself
item.remove()
item types
In my mind, there are really 3 types of items
normal items that you add to draw the stuff you want
this includes:
Ellipse, Image, Path, Polyline, Rect, and Text
Layout and gruop items include:
Group, Grid, and Table
And then there is also Widget. Widget is pretty cool.
You can add a gtk widget to your goocanvas, but note that it will live in a world seperate from the goocanvas
In other words, gtk.Widgets won't be rendered if you create images form our goocanvas and such
However, this is a cool way to add in situ editing to your goocanvas
We'll just be talking about normal items for the rest of this class though
general item capabilities
So what are some of the things that you do with an item? Well, you compose with it. So you scale it, move it, rotate it, change it's z-order and such
For a lot of things that you want to do with an item, you use set_property and get_property
For example, to set the a might make a Text item like this:
txt = goocanvas.Text(parent=self.root,text="some text", x=100, y=100, fill_color=self.ink_color)
then change the text in it like this:
txt.set_property("text","new text")
Let's look at colors for a moment. There are generally two color properties to work with, stork-color, and fill-color
If you've ever used a tool ink inkscape, this will make sense you to
for something like a rect, stroke-color is the outline of the rectangle, and fill-color is the inside of the rectangle
spacial transforms
You can move, rotate, resize, and skew items
The APIs for doing this are intuitive, imho
To grow something by 10%
item.scale(1.1,1.1)
And to shrink it a bit:
item.scale(.9,.9)
Note that the items always consider themeselves to be their original size and orientation, so doing this will cause an item to grow twice: item.scale(1.1,1.1) item.scale(1.1,1.1)
Now, when you start rotating and skewing items, some pretty confusing stuff can start happening
Essentially, an item tracks it's own coordinate system, and doesn't much care about the goocanvas's coordinate system
So if you rotate an item, for example, the coordinate systems are totally out of whack
So if you pass the x/ys to an item based on the canvas's coordinate system, it can get waaaay out of whack
Fortunately, goocanvas has some functions on it that just do these transforms for me
let's say I catch a mouse click event on an item
and I want to know where on the item the click happened
well, the click coordinate are reported in the goocanvas's coordinate system, so I need to do a quick calculation to determine where the click happened on the item:
e_x, e_y = self.goo_canvas.convert_to_item_space(self.selected_item,event.x,event.y)
Just a quick word on paths A path is essentially a "squiggle" It is defiened by a string that gets parsed into x,y coords, and then drawn with a bezier curve formula applied This is a bit of math that I don't much understand but just to get you started, here is a string that describes a scribble line_data = "M 4.0 4.0C4.0 4.0 5.0 4.0 5.0 4.0 5.0 4.0 6.0 4.0 6.0 3.0 10.0 1.0 13.0 2.0 9.0 15.0 6.0 36.0 28.0 11.0 28.0 11.0 29.0 11.0 33.0 12.0 33.0 15.0 32.0 19.0 27.0 51.0 27.0 53.0 27.0 54.0 27.0 54.0 27.0 54.0 36.0 49.0 37.0 49.0" then I can make a path out of this: path = goocanvas.Path(data=line_data, parent=self.Paths and clipping
so this will draw the path in the goocancas
Now, a path is also useful because you can use it to clip another object
You don't use a path object for this, just the string item.set_property("clip-path",line_data)
mousing
In terms of mousing, just fyi, a goocanvas has the normal gtk mouse tracking capabilities
to track mouse clicks, for example:
self.goo_canvas.connect("button_press_event",self.mouse_down) Remember to convert the coordinates from these events to item coordinates if needed!
Finally, a goocanvas can use cairo surfaces to render off snapshots of itself So if I want to make a png, I use an image surface x, y, w, h = self. There are other cairo surfaces as well, including a PDF surface rendering
UbuntuOpportunisticDeveloperWeek/GooCanvas (last edited 2010-03-02 14:28:45 by 71)