# WormGTK.py (c) Kari Laitinen # http://www.naturalprogramming.com # 2006-08-22 File created. # 2009-02-25 Last modification. # See notes at the end of this file. import gtk from threading import Thread from threading import Event from time import sleep #Initializing the gtk's thread engine gtk.gdk.threads_init() class AnimationThread ( Thread ) : def __init__( self, given_application ) : Thread.__init__( self ) self.host_application = given_application self.host_drawing_area = given_application.drawing_area self.thread_must_be_stopped = Event() print " thread init done " def stop_this_thread( self ) : self.thread_must_be_stopped.set() def redraw_and_sleep( self, given_sleeping_time ) : if not self.thread_must_be_stopped.isSet() : # Acquiring the gtk global mutex gtk.gdk.threads_enter() self.host_drawing_area.queue_draw() # Releasing the gtk global mutex gtk.gdk.threads_leave() # This method lets sleeping take place only if # the thread has not been ordered to 'die' if not self.thread_must_be_stopped.isSet() : sleep( given_sleeping_time ) def run( self ) : while not self.thread_must_be_stopped.isSet() : self.host_application.worm_position_x = 50 ; self.host_application.worm_length = 100 ; self.redraw_and_sleep( 2.000 ) # Delay of two seconds. while self.host_application.worm_position_x + \ self.host_application.worm_length < \ self.host_application.window_width and \ not self.thread_must_be_stopped.isSet() : for stretchings_counter in range( 7 ) : self.host_application.worm_length += 5 self.redraw_and_sleep( 0.050 ) # 50 milliseconds for shrinkings_counter in range( 7 ) : self.host_application.worm_position_x += 5 self.host_application.worm_length -= 5 self.redraw_and_sleep( 0.050 ) # 50 milliseconds self.redraw_and_sleep( 4.000 ) # Delay of 4 seconds. print " run method ends " class WormApplication : def __init__( self ) : self.application_window = gtk.Window( gtk.WINDOW_TOPLEVEL ) self.application_window.set_title( "ANIMATION BY USING A THREAD" ) self.application_window.connect( "destroy", self.exit_this_application ) self.application_window.set_size_request( 600, 330 ) self.drawing_area = gtk.DrawingArea() self.application_window.add( self.drawing_area ) self.drawing_area.connect( "expose-event", self.drawing_area_exposed ) self.drawing_area.show() self.application_window.show() self.window_width, self.window_height = \ self.application_window.get_size() self.worm_length = 100 ; self.worm_height = 30 ; self.worm_position_x = 50 ; self.worm_position_y = 150 ; self.ball_must_be_shown = False self.animation_thread = AnimationThread( self ) self.animation_thread.start() def drawing_area_exposed( self, area, event ) : graphics_context = \ self.drawing_area.get_style().fg_gc[gtk.STATE_NORMAL] this_drawable = self.drawing_area.window this_drawable.draw_rectangle( graphics_context, True, self.worm_position_x, self.worm_position_y, self.worm_length, self.worm_height ) return True def run( self ) : gtk.main() def exit_this_application( self, widget, data=None ) : self.animation_thread.stop_this_thread() gtk.main_quit() if __name__ == "__main__": this_application = WormApplication() this_application.run() # NOTES: # Double buffering is a means to prevent the flickering of a picture # that is drawn into a window. # Automatic double buffering is associated with widgets such as # DrawingArea objects. However, it it possible to switch off # the double buffering with a statement like # self.drawing_area.set_double_buffered( False ) # When double buffering is switched off it might be possible to # use images such as # self.offscreen_image = gtk.gdk.Pixmap( self.drawing_area.window, # self.window_width, # self.window_height )