Getting started with Multi-Touch Development in Python: Part 3

Its been a few weeks since I wrote a tutorial(or posted on this blog, for that matter), so I figured it was about time.  In this tutorial we will be starting from scratch, and using a different method to get touches.  At the end of this tutorial you will have used PyGame to write a program that will draw circles under each touch, and follow them as they move.  Most importantly, you will understand how to do it yourself!

Get started by firing up your favorite editor and making a new Python file.  I named mine PyTracer.py, but you can name it anything you want.

So, lets get started coding!

In this program I am going to take a new approach to doing tutorials.  I am going to give you the whole program, then explain it line by line, so you can easily skip over parts you understand, or read through the whole thing.

So, lets get started!

import sys

import pygame
from touch import touchpy

screen_dimensions = (1280, 1024)

t = touchpy()

pygame.init()
screen = pygame.display.set_mode(screen_dimensions, pygame.FULLSCREEN | pygame.NOFRAME)

while 1:
    screen.fill((0, 0, 0))
    t.update()

    for event in pygame.event.get():
        if event.type == pygame.QUIT or event.type == pygame.KEYDOWN:
            sys.exit()

    for blobid in t.blobs:
        x = int(round(t.blobs[blobid].xpos*screen_dimensions[0]))
        y = int(round(t.blobs[blobid].ypos*screen_dimensions[1]))

        if blobid % 2 == 0:
            pygame.draw.circle(screen, (232, 4, 40), (x, y), 50)

        else:
            pygame.draw.circle(screen, (40, 232, 20), (x, y), 50)

    pygame.display.flip()

So, now we can go through this line by line.  Before I start explaining that, notice a few things:

  • This program does not use any callbacks, unlike previous tutorials
  • To get touch events. we iterate the t.blobs dictionary
  • The main loop is most of the program, where it used to just be t.update()

Each of these will be explained in more detail as the tutorial goes on.

import sys

import pygame
from touch import touchpy

Here we import all the necessary libraries.  This is pretty self explanatory, but I will explain it anyway.  We import sys purely for sys.exit(), so we can exit whenever the user hits a key.  PyGame is the graphics library we use to draw the circles, so naturally we should import it.  If you have not played around with PyGame, you are missing out.  Check it out here, its an awesome graphics library.  Next is the line you should be used to seeing by now, importing the TouchPy library.  In case you have not read PEP 008, you should always differentiate between built in libraries, third party installed libraries, and local file includes by spacing them with newlines.  I highly recommend you read PEP 008 for tips on style in Python coding.  It makes your code a lot easier to read, and 99% of Python coders follow this standard.  It can be found here.

screen_dimensions = (1280, 1024)

You should also be familiar with this line. It is used to convert TouchPy coordinates into pixel coordinates. Of course, set this to your own screen resolution.

t = touchpy()

This line imports the TouchPy framework, and opens the network socket. TouchPy should always be the first thing you initialize in your program, because sometime it can take a long time to initialize. This way, it waits until TouchPy is ready to start the GUI. If you put this after the PyGame initialization it would open a window before it was ready, and then “stack up” touch events, then release them all at once when TouchPy was ready.

pygame.init()
screen = pygame.display.set_mode(screen_dimensions, pygame.FULLSCREEN | pygame.NOFRAME)

If you have had any experience with PyGame, this line should be very familiar, otherwise, Ill explain it. The first line initializes PyGame by going through each imported module and initializing it. The second line makes a screen for us to blit(copy images) onto. The first argument is the size(in pixels) of the window you want. We pass the screen size in, because we intend to make this program full screen. Then next arguments are graphics options, you can pass nothing in and it will run fine, but we want it to be full screen and have no frame. This is just fancy for saying override everything(panels, other windows), and hog mouse/keyboard input(don’t allow to lose focus until program exits).

while 1:
    screen.fill((0, 0, 0))
    t.update()

    for event in pygame.event.get():
        if event.type == pygame.QUIT or event.type == pygame.KEYDOWN:
            sys.exit()

    for blobid in t.blobs:
        x = int(round(t.blobs[blobid].xpos*screen_dimensions[0]))
        y = int(round(t.blobs[blobid].ypos*screen_dimensions[1]))

        if blobid % 2 == 0:
            pygame.draw.circle(screen, (232, 4, 40), (x, y), 50)

        else:
            pygame.draw.circle(screen, (40, 232, 20), (x, y), 50)

    pygame.display.flip()

This is our event loop.  All the action happens here, so, lets go through it.

    screen.fill((0, 0, 0))

This line clears the screen to black. If we did not have this line, it would act more like a paint program. Comment it out and try it. If you have never dealt with computer animation this may seem strange, but it makes sense once you get it(doesn’t everything:D). If this is new to you, I recommend you read this for a really quick intro to PyGame/Computer animation.

t.update()

This line should be very familiar by now, but it deserves an explanation all the same. This line calls the “update” method of theTtouchPy object. In this method it clears the event queue, then checks for new TUIO events through server.recv(0). If you were to comment out this line nothing would happen, because TouchPy would never check for new TUIO events.

    for event in pygame.event.get():
        if event.type == pygame.QUIT or event.type == pygame.KEYDOWN:
            sys.exit()

This is the code that lets you quit the program.  It will call sys.exit() on two conditions:

1.  It was told to quit by the OS(kill system call, close button clicked, system shutdown imminent, etc)

2.  A key was pressed on the keyboard

for blobid in t.blobs:
        x = int(round(t.blobs[blobid].xpos*screen_dimensions[0]))
        y = int(round(t.blobs[blobid].ypos*screen_dimensions[1]))

        if blobid % 2 == 0:
            pygame.draw.circle(screen, (232, 4, 40), (x, y), 50)

        else:
            pygame.draw.circle(screen, (40, 232, 20), (x, y), 50)

This is where the real magic happens. Here it gets the coordinates of all the touches, and draws circles there. The for loop is iterating through the list blobs, which is an attribute of the TouchPy object, t.  t. blobs is a dictionary of blobIDs and Tuio2DCursor Objects.  We iterate through the list of blobIDs, then use that as the index to get the actual Tuio2DCursor Object.  Then next two lines get the x and y position in coordinates.  If you don’t understand this, you should go back and (re)read part two.

        if blobid % 2 == 0:
            pygame.draw.circle(screen, (232, 4, 40), (x, y), 50)

        else:
            pygame.draw.circle(screen, (40, 232, 20), (x, y), 50)

This is where the circles get painted. All the if statement is for is just to add some pizazz to the program. It just colors every other blob red or green. You could replace the whole if statement with one of the circle paint statements and it would still work fine. Speaking of circle paint statements, this is a PyGame function for drawing a circle. It does not need an image to be blitted, you just pass it the screen you want it on, color, position, and radius.

pygame.display.flip()

In computer animation there are really two images of the screen. The one that is being shown, and the one that you are modifying. Every time you want something new to show up you flip them, so you show the one you modified, then modify the other one. If this doesn’t make sense you should read the PyGame into here.

That concludes this tutorial. I think the rest of the tutorials will follow this form, except maybe the first few after Python-Lux comes out. I appreciate all feedback, and would love to hear how well this tutorial went for you. Also, if you have any ideas for a tutorial, let me know:) I am going to try and do about one every two weeks, and see how that goes. Thanks for reading!

Other interesting Python stuff you may want to read:

6 comments so far

  1. Erik on

    Great tutorials, please keep them coming!

    What happened to the python-lux channel on irc? doesnt seem to exist anymore 😦

  2. xelapond on

    Thanks! If you have any ideas for tutorials please let me know, I can’t think of where to go from here.

    As for python-lux, it doesn’t really have a point. Feel free to ask python questions on #nuigroup. Ill try and be on IRC more, but life has its way of getting in the way of things:)

  3. Erik on

    does python do threading? if so, might be a cool thing to explain. or perhaps python and openGL.

    ye life does that

  4. xelapondsstuff on

    Python does do threading. There are many modules for this, multiprocessing, multithreading, and pyqt to name a few. I would check their documentations, I don’t see what I could explain the the documentation can’t.

    What nick do you use on IRC? I have never seen “eric” on #nuigroup:)

  5. james007 on

    Xela,

    Can you make a tutorial, if you touch a certain command button
    then an event will happen..^_^

    • xelapondsstuff on

      I’m on it:)


Leave a comment