Monday 27 April 2009

Using pygame to develop with context free

A problem I have had while playing round with Context Free, is that every time I change the cfdg file, I have to rerun cfdg and then display the resulting image. This got me thinking that there must be a good way to monitor the file and every time it changes just re-run and display the image. My mind wondered back to a pycon UK when I saw a guy using pygame to display his slides. The reason being that as pygame is essentially a framework for displaying images and handling events without the tedious bits around the edges, he could very easily create a slide show that could run on anything without an extra program required. Putting this to work against my problem I could just create a python app that would monitor the file and every time the file changed, rerun cfdg and display the image in pygame. It turns out that this is ridiculously easy: 1) Initialise a pygame window 2) Start a thread to monitor the file. The thread just runs the cfdg with popen and displays the image created to the pygame window. I found it better to just run every second that way I could see the different images created by the random branching in context free. 3) Keep going till a keystoke kills the process. So here it is (python 2.5):
import pygame, sys, threading, time, os
pygame.init()

def setupScreen(width, height):
    screen = pygame.display.set_mode( (width,height) )
    pygame.display.flip()
    return screen
    
def waitForKeyStroke():
    runProgram = True
    while runProgram:
        event = pygame.event.wait()
        if event.type == pygame.QUIT or event.type == pygame.KEYDOWN:
            runProgram = False

def displayImage( screen, path ):
    px = pygame.image.load(path)
    screen.blit(px, px.get_rect())
    pygame.display.flip()
    return px

class updator(object):
    
    def __init__(self, screen, cfdgPath, imagePath):
        self.running = True
        self.screen = screen
        self.cfdgPath = cfdgPath
        self.imagePath = imagePath
        self.updatePeriod = 1

    def updateScreen(self):
        while self.running:
            f = os.popen('cfdg %s %s' % (self.cfdgPath, self.imagePath))
            txt = f.read()
            if f.close():
                print txt
            displayImage(self.screen,self.imagePath)
            time.sleep(self.updatePeriod)

def mainLoop(screen, cfdgPath, imagePath):
    u = updator(screen,cfdgPath,imagePath)
    t = threading.Thread(target=u.updateScreen)
    t.start()
    waitForKeyStroke()
    u.running = False
    t.join(10)
    
if __name__ == "__main__":
    "Usage cfdgviewer.py  "
    screen = setupScreen(500,500)
    mainLoop(screen, sys.argv[1], sys.argv[2])

No comments: