An introduction to pyclutter (part three)
October 22nd, 2007
This tutorial is outdated: it refers to version 0.4 of clutter that now is VERY old.
Last time we have seen how to draw the (maybe) most basic shape of clutter: the rectangles. We also positioned them together in the stage, and said (in part one) that the stage is a special kind of container.
Today it’s time to explain better what groups are and how to use them, so I’ll introduce to you the ClutterGroup and the ClutterHBox/ClutterVBox.
In the first part of this tutorial we said that the stage is a top level “window” on which child actors are placed and manipulated. That’s correct, but we also said that a stage is a special kind of container. Container, but it is self explanatory, contains objects: in the clutter’s case, these objects can be other containers or actors.
If you have some experience with GTK, you know that GTK uses HBox and VBox for placing the widgets respectively horizontally and vertically. Clutter has the same concept with ClutterHBox and ClutterVBox but, since clutter uses 3D effects, we also have a depth dimension, and we must be able to handle it in some way. Here comes the ClutterGroup: it contains objects exactly like HBox/VBox, but they’re not added sequentially horizontally or vertically, they’re added one up the other. Additionally, with ClutterGroups, we can use the relative positioning (we’ll see how later).
But before to talk about groups, it’s better to talk about HBox/VBox. I already said that HBox or VBox are used to place actors (or even other containers) sequentially. That said, if we add a label to a HBox and then we add a rectangle, the label and the rectangle will be placed sequentially starting from left.
Maybe it’s better to see this behaviour directly in action:
import clutter
def main():
stage = clutter.stage_get_default()
stage.set_size(420, 200)
stage.set_color(clutter.color_parse("#FFF"))
hbox = clutter.HBox()
hbox.set_position(10, 10)
rect_h1 = clutter.Rectangle()
rect_h1.set_size(200, 50)
rect_h1.set_color(clutter.color_parse("#FF0000"))
rect_h2 = clutter.Rectangle()
rect_h2.set_size(200, 50)
rect_h2.set_color(clutter.color_parse("#800000"))
rect_h2.set_border_width(1)
rect_h2.set_border_color(clutter.color_parse("#000000"))
vbox = clutter.VBox()
vbox.set_position(10, 80)
rect_v1 = clutter.Rectangle()
rect_v1.set_size(200, 50)
rect_v1.set_color(clutter.color_parse("#00FF00"))
rect_v2 = clutter.Rectangle()
rect_v2.set_size(200, 50)
rect_v2.set_color(clutter.color_parse("#008000"))
rect_v2.set_border_width(1)
rect_v2.set_border_color(clutter.color_parse("#000000"))
rect_h1.show()
rect_h2.show()
rect_v1.show()
rect_v2.show()
hbox.add(rect_h1, rect_h2)
vbox.add(rect_v1, rect_v2)
stage.add(hbox, vbox)
hbox.show_all()
vbox.show_all()
stage.show_all()
stage.connect("key-press-event", clutter.main_quit)
clutter.main()
if __name__ == '__main__':
main()
The above code will produce this:
You may ask yourself why we use multiple show() instead of having a single show_all() on the stage. The reason is that show_all() doesn’t recurse inside a Group because you might be hiding some of the actors inside that group for a later use. Anyway, it’s possible to subclass a clutter.Group and override the show_all() method so it recurse inside all its children, but that’s a bit more advanced topic that I hope I’ll be able to cover in another part of the tutorial.
As you can see, the rectangles have been placed sequentially in horizontal (for the HBox) or vertical (for the VBox) direction. In this way we can build a basic interface, since we can have nested boxes, that said HBoxes that contains other HBoxes or VBoxes (this is true for VBox too, obviously):
import clutter
def main():
stage = clutter.stage_get_default()
stage.set_size(420, 200)
stage.set_color(clutter.color_parse("#FFF"))
hbox = clutter.HBox()
hbox.set_position(10, 10)
rect_h1 = clutter.Rectangle()
rect_h1.set_size(200, 50)
rect_h1.set_color(clutter.color_parse("#FF0000"))
vbox = clutter.VBox()
vbox.set_position(10, 80)
rect_v1 = clutter.Rectangle()
rect_v1.set_size(200, 50)
rect_v1.set_color(clutter.color_parse("#00FF00"))
rect_v2 = clutter.Rectangle()
rect_v2.set_size(200, 50)
rect_v2.set_color(clutter.color_parse("#008000"))
rect_v2.set_border_width(1)
rect_v2.set_border_color(clutter.color_parse("#000000"))
rect_h1.show()
rect_v1.show()
rect_v2.show()
vbox.add(rect_v1, rect_v2)
hbox.add(rect_h1, vbox)
stage.add(hbox)
hbox.show_all()
vbox.show_all()
stage.show_all()
stage.connect("key-press-event", clutter.main_quit)
clutter.main()
if __name__ == '__main__':
main()
It works in this way:
Let do a step back: we introduced the set_position method previously, but we didn’t explained extensively how this method works. The set_position set the specified actor’s position to the coordinates relatives to its father container. So, if we don’t have any container it reverts to the stage, that is the father of all the childs in a window (and we have absolute positioning), otherwise it will set the actor’s position to the first father it finds. Let see this scheme to clarify a bit:

Groups shares most of the properties of HBox and VBox, but instead of placing the elements horizontally or vertically, it positions them on the z-axis (it put the actors one up the other). In this way we can also have a container that help us in achieving the relative positioning:
import clutter
def main():
stage = clutter.stage_get_default()
stage.set_size(500, 500)
stage.set_color(clutter.color_parse("#FFF"))
rect1, rect2, rect3 = clutter.Rectangle(), clutter.Rectangle(), clutter.Rectangle()
group1, group2, group3 = clutter.Group(), clutter.Group(), clutter.Group()
group1.add(rect1, group2)
group2.add(rect2, group3)
group3.add(rect3)
group1.set_position(100, 100)
group2.set_position(100, 100)
group3.set_position(100, 100)
rect1.set_position(0, 0)
rect2.set_position(0, 0)
rect3.set_position(0, 0)
rect1.set_size(150, 150)
rect2.set_size(150, 150)
rect3.set_size(150, 150)
rect1.set_color(clutter.color_parse("#FF000090"))
rect2.set_color(clutter.color_parse("#00FF0090"))
rect3.set_color(clutter.color_parse("#0000FF90"))
stage.add(group1)
stage.show_all()
group1.show_all()
group2.show_all()
group3.show_all()
stage.connect("key-press-event", clutter.main_quit)
clutter.main()
if __name__ == '__main__':
main()
With the above code, we’ll position each group relatively to its father. Only the first group will have the stage as father, all the others are relative positioned to the previous stage.
That’s all for today :)
Great tutorial. So..when can we expect part 4? :)
Comment by Sadhu — December 20th, 2007 at 20:26
I do really hope before the end of the year… I’ve been quite busy ultimately, but the part 4 is on the way :)
Comment by Giuliani Vito, Ivan — December 21st, 2007 at 11:05
I know this is a complicated idea, but this is one of the few places that I can find that is doing work with pyclutter.
I was wondering how I can extend an actor? I found a C Tutorial about clutter and they showed how to create a TriangleActor, I was wondering how hard this would be for pyclutter?
Thanks for any help you can give.
Comment by Andy B. — January 5th, 2008 at 2:37
I’m not sure that this kind of stuff can be done with pyclutter. For that you should do your cpython extension. Anyway, I have to check since a lot of new stuff joined clutter 0.6 and I’m still too busy to look at the improvements that the clutter staff done.
Comment by Giuliani Vito, Ivan — January 13th, 2008 at 14:52
This code doesn’t seem to work with clutter 0.6.
Comment by Charclo — March 24th, 2008 at 12:13
yes, it doesn’t work on py clutter 0.6 :
hbox = clutter.HBox()
AttributeError: ‘module’ object has no attribute ‘HBox’
where are this boxes defined?
Thanks! this tutorials are great!
Comment by Cristian — July 6th, 2008 at 1:53
Yes, the tutorials are outdated, they’re based upon clutter 0.4 (and since then too many things have changed). I should add a note about this, anyway…
Comment by Giuliani Vito, Ivan — July 6th, 2008 at 10:40
Great tutorials! Thanks for taking time to put these together … hoping you’ll be able to extend them as well. These are great for those of us just learning ..
Comment by Brian — September 24th, 2008 at 16:58