1
votes

people

I have seen some tutorials showing how to create animations with PyGtk, the best one being this:

https://cairographics.org/cookbook/animationrotation/

This tutorial uses gobject.timeout_add() to set some clock to constantly refresh the animation.

What I wanted to do, instead, is to create FINITE animations, which I could trigger by clicking in some button or checkbox or anything.

For example, I could have a Window with a Button and a DrawingArea with a ball drawn. When I click the button, the ball would go up and down, and stop. If I click the button again, the ball repeats the move.

In another scenario, the ball could be on the left of the screen. When I toggle a CheckBox, the ball goes (not instantly, but rather moves in a transition) to the right. If I uncheck, the ball comes back to its original position.

I am not planning to use anything else than pure Cairo/Gtk (no Clutter, no OpenGL, no PyGame), because I feel that it should be possible, and I want to go on studying Gtk to do some (future) GUI tricks with simple one-file scripts.

Since the question is about a broader problem, I think it is not needed to add code, but I could edit this question to put some code if anyone feels it would be better.

Thanks for reading and for any help! And Cairo/Gtk is great!

EDIT: after the precise explanation from Jeremy Flores, I came out with this code, which is useless (the ball goes to the right each time the button is clicked, untill falling off the window), but contains the elements upon which to build more creative and useful stuff. If anyone (including Jeremy) has anything to say about this code, specially about removing unnecessary parts, I would very gladly like to hear. Thanks!

#!/usr/bin/env python
import gtk, gobject
from math import pi

class Canvas(gtk.DrawingArea):
    def __init__(self):
        super(Canvas, self).__init__()
        self.connect("expose_event", self.expose)
        self.set_size_request(400,400)

        self.x = 20
        self.y = 20

        self.counter = 0

    def movealittle(self):
        self.x += 1
        self.counter += 1
        self.queue_draw()
        if self.counter <= 20:
            return True
        elif self.counter > 20:
            self.counter = 0
            return False

    def expose(self, widget, event):
        cr = widget.window.cairo_create()
        rect = self.get_allocation()

        w = rect.width
        h = rect.height

        cr.arc(self.x, self.y, 10, 0, 2*pi)
        cr.fill()

def runanimation(widget):
    gobject.timeout_add(5, canvas.movealittle)
    print "runanimation call"

button = gtk.Button("Move")
button.connect("clicked", runanimation)

window = gtk.Window()
canvas = Canvas()
panel = gtk.VBox()
window.add(panel)
panel.pack_start(canvas)
panel.pack_start(button)
window.set_position(gtk.WIN_POS_CENTER)
window.show_all()
gtk.main()
1
Also see gtk-window-motion-animation for comments on avoiding animation jitter even if timer callbacks are at irregular intervals. Includes C-code example.James Waldby - jwpat7

1 Answers

4
votes

gobject.timeout_add() can be used for finite animations. The callback you set up will keep being called until it returns False, at which point your method won't be called again.

For example, if you want a ball to be animated for 5 seconds, you would be responsible for determining how long the animation has been going, and then once it has passed 5 seconds, your method would return False to end the animation. When you want the animation to start again, simply re-register the callback with timeout_add and reset your time counter.

See: http://www.pygtk.org/pygtk2reference/gobject-functions.html#function-gobject--timeout-add for more information.