Skip to content

Writing a pyprocessing application

Claudio Esperança edited this page Oct 10, 2016 · 1 revision

Pyprocessing works in much the same fashion as Processing. In fact, most functions in pyprocessing mimic the equivalent Processing functions to the letter. If you are familiar with Processing and Python, you already know almost everything you need to write pyprocessing applications. To cut a long story short, the only thing you need to do is to import the pyprocessing package, write the rest of your code using pyprocessing functions and data structures, and call run().

Simple usage

Unlike Processing, pyprocessing is not a full fledged IDE but merely a Python package. Thus, you must use your favorite text editor or Python IDE to write a regular Python program which imports the pyprocessing package. We suggest doing it at the beginning of your application:

from pyprocessing import *

After the import, a default 100x100 pixel window is defined, on which the application may now draw using pyprocessing functions and other Python commands. For instance:

smooth()
for i in range(10):
    line(i*5+5,20,i*5+50,80)

The last instruction should be a call to the run() function:

run()

When this line is reached, the graphics window, which was hidden until this point, will finally be shown and the application will enter the event dispatching loop. In principle, run() does not return, but you can terminate the application by typing the ESC key.

In case you're wondering, here's the complete script and the contents of the drawing:

from pyprocessing import *

smooth()
for i in range(10):
line(i*5+5,20,i*5+50,80)

run()

Changing the default window

As with Processing, the window size may be changed with the size() function. It has two required arguments: the width and height of the desired window in pixels. Thus,

size(200,200)

will open a 200x200 pixels window.

By default, pyprocessing windows are not resizable, since this is the expected Processing behavior. You can, however, request a resizable window by adding the keyword argument resizable=True:

size(200,200,resizable=True)

It is even possible to request a full screen window by using the keyword argument fullscreen=True.

Pyprocessing will adjust the coordinate system to reflect the changed window dimensions. Thus, if the window is resized so that it is now 250 pixels wide and 150 pixels high, the pixels will be addressed by x in interval [0, 250) and y in interval [0, 150), where pixel (0,0) is the top left corner of the window, i.e., the y axis points down.

Of course, if the window is resized, the original contents drawn so far will be lost, and pyprocessing will automatically call the draw() function you defined in your program, if any (see the next section).

Animation

In order to do animations or to deal with resizing windows, the application must define a callback function called draw(). By default, draw() is called continuously 60 times per second.

Pyprocessing also supports the setup() callback convention, i.e., if you define a function called setup(), it will be called exactly once by run(). Notice that in Processing, so called static programs -- or sketches in Processing parlance -- do not define any functions (callbacks or otherwise), while the initialization of a program with a draw() is almost always performed by setup(). On the other hand, pyprocessing is less strict, i.e., you can put initialization code inside a setup() function or directly in the main program regardless of whether a draw() callback function was defined or not.

In the example below, which implements an animation with two balls, setup() is automatically called once to initialize the screen and some drawing modes, whereas draw() is called repeatedly to update the balls array and draw the frame.

from pyprocessing import *

balls = [(20,20,2.5,3,10),(100,50,-3.5,-3,15)]

def setup():
size(150,150)
ellipseMode(CENTER)
noStroke()

def draw():
fill(200,50)
rect(0,0,150,150)
fill(0)
for i in range(len(balls)):
x,y,dx,dy,r = balls[i]
x += dx
if constrain(x,r,150-r) != x: dx = -dx
y += dy
if constrain(y,r,150-r) != y: dy = -dy
balls[i] = x,y,dx,dy,r
ellipse(x,y,r,r)

run()

Interaction

An interactive application must process user input such as mouse clicks or keyboard typing. Again, following Processing's practice, the state of input devices is kept in global variables which can either be polled in your draw() function or queried only when their value changes by means of callback functions.

The example program shown below illustrates a simple scribbling application where dragging the mouse paints freehand lines and hitting the 'C' key clears the screen.

from pyprocessing import *

size(200,200)

def draw():
# scribble a line with the mouse
if mouse.pressed:
line (pmouse.x, pmouse.y, mouse.x, mouse.y)
# typing 'C' clears the screen
if key.pressed and key.char in 'cC':
background(200)

run()

The same application can be rewritten in a more efficient manner by using callback functions:

from pyprocessing import *

size(200,200)

def mouseDragged():
    # scribble a line with the mouse
    line (pmouse.x, pmouse.y, mouse.x, mouse.y)
    
def keyPressed():
    # typing 'C' clears the screen
    if key.char in 'cC':
        background(200)

run()

A note about state variables

Due to the characteristics of the Python language, pyprocessing uses a naming for state variables that is slightly different from the one used by Processing. For instance, whereas Processing uses the boolean variable mousePressed to tell whether or not a mouse button is pressed, the equivalent variable in pyprocessing is named mouse.pressed. The reason for this is that Java -- the actual programming language that underlies Processing -- allows identifiers to be overloaded and thus it is perfectly alright to have a variable named mousePressed and a function called mousePressed() while in Python this is not allowed.

Clone this wiki locally