This is a machine-generated translation, meant to support the in-person workshop.
Now we will show you how to write a graphical application.
The Python language itself contains tools for drawing images, but they are not very suitable for creating games. Therefore, we will use a library (extension) called Pyglet, which is specifically built for interactive graphics.
But we have to install it separately first. The safest way is to enter the following two commands into the command line with the virtual environment turned on. (There are also simpler ways, but they require a "correctly" configured system.)
pip tool, which is capable of installing libraries for Python:
(venv)$ python -m pip install --upgrade pip
(In translation: Python, run the module pip and tell it to install and optionally upgrade the pip library.)
Installing Pyglet itself:
(venv)$ python -m pip install pyglet
(In translation: Python, run the module pip and tell it to install the pyglet library.)
For me, the installation looks something like this:
(venv)$ python -m pip install --upgrade pip Requirement already satisfied: pip in ./venv/lib/python3.6/site-packages (18.0) (venv)$ python -m pip install pyglet Collecting pyglet Downloading pyglet-1.2.4-py3-none-any.whl (964kB) Installing collected packages: pyglet Successfully installed pyglet-1.2.4
The important thing is "Successfully installed", or "Requirement already satisfied" at the end. This means that the library is ready to use!
Now try to create a new file in the editor, save it as
graphics.py, and write the following program in it:
import pyglet window = pyglet.window.Window() pyglet.app.run() print('Done!')
Run it. A black window should appear.
Is the window not black? On some computers (often with macOS and some types of Linux), it happens that the window is not black, but there is some "mess" in it. That's okay. Before we start drawing in the window, we >will clean up the mess.
If you receive the error `AttributeError: module 'pyglet' has no attribute 'window'`, check that you named the file `graphics.py` and not `pyglet.py`. Save the file in the editor as `graphics.py`, delete any file named >`pyglet.py`, and try again.
Graphics are a sensitive matter - you are using a system with many parts that can break (Python, Pyglet, OpenGL, graphics card and its driver, operating system, ...). If it doesn't work for you, it's best to consult with an expert.
Done? Let's explain what is happening in this program.
import pyglet will give you access to the graphics library, just like
import random gives you access to functions related to random numbers.
The call to
pyglet.window.Window() creates a new window on the screen. It returns an object that can be used to control this window; it is stored in the variable
The call to
pyglet.app.run() then launches the application.
The simple programs you have written so far are descriptions of a process - similar to cooking recipes. A sequence of steps that Python executes sequentially from the first to the last. Sometimes something is repeated and some steps can be "wrapped" into a function, but we have always described one procedure from beginning to end so far.
Programs for more complex applications look more like a manual for a car mechanic than a recipe. They describe what should happen in a given situation. For example, a program for a text editor could look like this:
And such a program can be written as a "recipe" - but that recipe is the same for all applications:
And that is exactly what
pyglet.app.run() does. It processes events, situations that need to be responded to. In your program, it currently responds to the window close button and the Esc key by closing the window and exiting.
Your programming task now is to describe what other events are interesting and how to respond to them.
The easiest event you can handle is typing on a keyboard.
Try putting the following code just above the line 'pyglet.app.run()' in the program:
@window.event def on_text(text): print(text)
What is this?
It is a function definition, but at the beginning it has a decorator - the line starting with an at sign.
window.event decorator is a way to tell Pyglet to run this function when something interesting happens.
What's interesting? Pyglet finds out based on the function name: 'on_text' reacts to text. Whenever the user presses a key, Pyglet calls your function!
And what does your function do? It calls
print() function still outputs text to the same place as before.
Just because a graphical window is open doesn't mean that everything will suddenly start writing to it.
How to write in a textbox? That is a bit more complicated than in a console. The text in the box can have different colors, sizes, fonts, and can be shifted or rotated in various ways.
All these font attributes need to be saved (along with the text itself) in the
Label object (meaning 'label'). Try it - put the following code under the line with
label = pyglet.text.Label("Ahoj!", x=10, y=20)
In the variable
label you will now have a label with the text "Hello" that belongs to position (10, 20) - 10 points from the right edge of the window and 20 points from the bottom.
Other properties besides position are not specified here, so reasonable "default" values will be used: white color, small but readable font.
The caption, however, will not write itself. Similarly to calling
on_draw - is necessary to draw text.
Put this code under the
@window.event def on_draw(): window.clear() label.draw()
This function is called by Pyglet whenever it is necessary to draw the content of the window. In animations (movies or games), this is often required 60 times per second ("60 FPS").
The function does two things:
In the window, you will now see a greeting!
Try changing the
on_text function so that the entered text is displayed in a window instead of on the console. This is done by assigning the text to the attribute
@window.event def on_text(text): print('Starý text:', label.text) label.text = text print('Nový text:', label.text)
Can you add new text to the old one in this function so that the program works as a simple text editor?
What other events can be responded to? They are all described in the Pyglet documentation (https://pyglet.readthedocs.io/en/latest/modules/window.html#pyglet.window.Window.on_activate). Here are a few interesting ones.
The keys that do not enter text (arrows, Backspace or Enter, etc.) can be recognized in the
on_key_press has two arguments: the first one is the keycode, which you can compare with a constant from pyglet.window.key. The second one determines the pressed modifiers such as Shift or Ctrl.
@window.event def on_key_press(key_code, modifier): if key_code == pyglet.window.key.BACKSPACE: label.text = label.text[:-1] if key_code == pyglet.window.key.ENTER: print('Zadaná zpráva:', label.text) window.close()
On macOS, you may need to replace
DELETE. (Or at home, study the method for doing it automatically and correctly.)
When handling the
on_mouse_press event, you will receive information about the position of the click (the x and y coordinates) as well as information about the mouse button and modifier that was pressed.
Like this, for example, the caption will move to the location of the click:
@window.event def on_mouse_press(x, y, button, modifier): label.x = x label.y = y
A slightly different type of event is the ticking of a clock: something that occurs regularly.
This is how animations are created, when something on the screen changes and is redrawn very often - for example, 60 times per second.
How to do it in Pyglet?
Once again, it is necessary to define a function, but this time it will not be enough to just use
Pyglet needs to know how often to call the function.
Tell it by calling
pyglet.clock.schedule_interval with two arguments:
the name of the function and the time between each call - ¹/₆₀ seconds.
Write all of this again before the line
def tik(dt): label.x = label.x + 1 pyglet.clock.schedule_interval(tik, 1/60)
Pyglet now moves the text 1 pixel to the right every sixtieth of a second.
In case you get lost or don't know where a particular piece of code belongs, I am providing a sample program for reference.
import pyglet window = pyglet.window.Window() label = pyglet.text.Label("Hello!", x=10, y=20) @window.event def on_draw(): window.clear() label.draw() @window.event def on_text(text): label.text = label.text + text @window.event def on_key_press(key_code, modifier): if key_code == pyglet.window.key.BACKSPACE: label.text = label.text[:-1] if key_code == pyglet.window.key.ENTER: print('Zadaná zpráva:', label.text) window.close() @window.event def on_mouse_press(x, y, button, modifier): label.x = x label.y = y def tik(dt): label.x = label.x + 1 pyglet.clock.schedule_interval(tik, 1/60) pyglet.app.run()
So much for the training graphic application. What have you learned
pygletmodule creates a window.
@window.eventmarks a function that Pyglet will call in response to a certain event: keyboard input (
on_text), drawing (
on_draw), key press (
pyglet.app.run(), you tell Pyglet that everything is set up and it should start the application.