×
produktlogotitle

 DOWNLOADSEITE

Seite: ha_events
Diese Seite wurde aktualisiert am 30.09.2025

LOGIN
Benutzer:
Passwort:
 
Geogebra-
   ifwp.net-schulbuch.de
Startseite Projekte Projekte: Kapitel 1 Diese Seite wurde aktualisiert am 30.09.2025

Event-Bearbeitung in Pygame

Event ist der engliche Begriff für Ereignis. Jedes Pygame-Programm hat eine interne Schleife, die ständig prüft, ob ein Event aufgetreten ist – also zum Beispiel, ob eine Taste gedrückt, die Maus bewegt oder eine Maustaste betätigt wurde.

Alle eingetretenen Events werden von Pygame automatisch in einer Liste gespeichert. Jedes Event enthält neben dem Typ des Events (z. B. MOUSEBUTTONDOWN, MOUSEBUTTONUP, MOUSEMOTION, KEYDOWN) auch zusätzliche Informationen – etwa die Position der Maus, welche Maustaste gedrückt wurde  oder welche Taste der Tastatur gedrückt wurde.

Mit dem Befehl pygame.event.get() kann man die Liste der aktuellen Events abrufen. Um diese zu bearbeiten, wird oft eine Funktion wie handle_events()) verwendet, die in einer Schleife alle Events einzeln verarbeitet. Als erstes Beispiel hast du in der Einführung schon kennengelernt, wie durch Betätigen der rechten Maustaste ein Pygame-Programm beendet wird.

 

Das folgende Programm zeichnet bei jedem Mausklick der linken Maustaste einen roten Kreis mit dem Radius 20 an der Mausposition.

Programm 7

import pygame

WIDTH = 650
HEIGHT = 450
BLUE = (0, 0, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
LIGHTGREY = (240, 240, 240)


def init():
    pygame.init()
    screen = pygame.display.set_mode((WIDTH, HEIGHT))
    screen.fill(LIGHTGREY) 
    pygame.display.flip()
    return screen


def handle_events():
    global screen
    for event in pygame.event.get():
        if event.type == pygame.MOUSEBUTTONDOWN:
                if event.button == 3:  # Rechte Maustaste
                    return False
                elif event.button == 1:
                    pygame.draw.circle(screen, RED, event.pos, 20)
                    return True
    return True

def main():
    global screen
    clock = pygame.time.Clock()
    screen = init()
    running = True
    while running:
        running  = handle_events()
        pygame.display.flip()
        clock.tick(60)
    pygame.quit()

main()

Erläuterung

Wir erläutern die Funktion handle_events beginnend in Zeile 19. zeilenweise.

Zeile Erläuterung
20 Die Variable screen, die die Zeichenfläche darstellt, wird hier als global deklariert, damit sie auch innerhalb der Funktion handle_events() verwendet werden kann. Alternativ hätte man sie als Parameter übergeben können.
21 Mit pygame.event.get() wird die Liste aller Ereignisse (Events) abgefragt, die seit dem letzten Aufruf aufgetreten sind. Diese werden in einer Schleife einzeln durchlaufen.
22 Es wird geprüft, ob es sich bei dem aktuellen Event um ein Maustastendruck-Ereignis (MOUSEBUTTONDOWN) handelt.
23 - 24 event.button gibt an, welche Maustaste gedrückt wurde. Die rechte Taste hat den Wert 3, die linke den Wert 1. Wird rechts geklickt, wird das Programm beendet (False wird zurückgegeben).
25 - 26 Bei einem linken Mausklick wird ein Kreis an der aktuellen Mausposition gezeichnet. Die Koordinaten des Mausklicks erhält man über event.pos. Danach wird True zurückgegeben, damit das Programm weiterläuft.
Icon Aufgabe 30x30 Auftrag

Teste das Programm in Webtigerpython. Was ändert sich, wenn du MOUSEBUTTONDOWN durch MOUSEBUTTONUP ersetzt?

Bei MOUSEBUTTONDOWN wird der Kreis gezeichnet, sobald die Maustaste gedrückt wurde, bei MOUSEBUTTONUP erst dann, wenn die Maustaste losgelassen wurd.

Farbwechsel bei Klick auf Kreis
Jetzt entwickeln wir ein Programm, das bei einem Klick auf einen Kreis dessen Farbe zufällig ändert. Damit das funktioniert, müssen wir wissen, ob die Maus innerhalb des Kreises geklickt wurde. Dafür speichern wir die Daten des Kreises wieder in einem Dictionary. Dazu benötigen wir einige Hilfsfunktionen, die wir zum großen Teil schon besprochen haben. 

def get_circle_dict(x, y, r, col, dx, dy):
    return {"x":x, "y":y, "radius": r, "color":col,"dx":dx, "dy":dy}

def draw_circle(screen,c):
    pygame.draw.circle(screen, c["color"], ( c["x"],c["y"]), c["radius"])

def get_random_color():
    return (random.randint(0,255),random.randint(0,255),random.randint(0,255))

Die Funktionen get_circle_dict und draw_circle sind bereits bekannt. Die Funktion get_random_color liefert eine Zufallsfarbe, indem die drei RGB_Werte zufällig aus dem Bereich von 0 bis 255 bestimmt werden. In der main-Funktion wird durch Aufruf der Funktion get_circle_dict ein Kreis erzeugt und in der Programm-Schleife gezeichnet. Diesmal übergeben wir die Variablen screen und circle an die Parameter der Funktion handle_events.

def main():
    clock = pygame.time.Clock()
    screen = init()
    running = True
    circle = get_circle_dict(300, 200, 50, get_random_color(),0,0)
    while running:
        screen.fill(LIGHTGREY)
        draw_circle(screen, circle)
        pygame.display.flip()
        running = handle_events(screen, circle)
        clock.tick(60)
    pygame.quit()

Fehlt nur noch die Weiterentwicklung von handle_events. Die Funktion hat die Aufgabe, die Farbe des Kreises zu ändern, wenn die Mausposition beim Klick innerhalb des Kreises war. Um das zu prüfen, schreiben wir die Funktion contains(c, pos), die True zurückliefert, wenn die Mausposition pos innerhalb des Kreises c liegt. Das ist der Fall, wenn der Abstand des Mittelpunktes des Kreises von der Mausposition kleiner als der Radius des Kreises ist.  Wir berechnen den Abstand mithilfe der Funktion hypot(d1, d2) aus der Bibliothek math. Wenn die Parameter d1, d2 die Differenzen der x- und y-Koordinaten zweier Punkte sind, berechnet die Funktion den Abstand der beiden Punkte. Wenn man die Differenzen als Länge der Katheten eines rechtwinkligen Dreiecks betrachtet, berechnet die Funktion die Länge der Hypotenuse des rechtwinkligen Dreiecks, die dem Abstand der beiden Punkte entspricht. Damit ergibt sich folgende Funktion:

def contains(c, pos):
    if math.hypot(pos[0] -c["x"], pos[1] - c["y"]) < c["radius"]:
        return True
    return False

Icon Aufgabe 30x30 Auftrag   

Implementiere mithilfe der entwickelten Funktionen das vollständige Programm und teste es. Beachte, welche Bibliotheken du importieren musst.

Programm 8
import pygame
import random
import math

WIDTH = 650
HEIGHT = 450
BLUE = (0, 0, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
LIGHTGREY = (240, 240, 240)


def init():
    pygame.init()
    screen = pygame.display.set_mode((WIDTH, HEIGHT))
    screen.fill(LIGHTGREY) 
    pygame.display.flip()
    return screen

def get_circle_dict(x, y, r, col, dx, dy):
    return {"x":x, "y":y, "radius": r, "color":col,"dx":dx, "dy":dy}

def draw_circle(screen,c):
     pygame.draw.circle(screen, c["color"], ( c["x"],c["y"]), c["radius"])

def get_random_color():
    return (random.randint(0,255),random.randint(0,255),random.randint(0,255))

def contains(c, pos):
    if math.hypot(pos[0] -c["x"], pos[1] - c["y"]) < c["radius"]:
        return True
    return False

def handle_events(screen, circle):
    for event in pygame.event.get():
        if event.type == pygame.MOUSEBUTTONDOWN:
                if event.button == 3:  # Rechte Maustaste
                    return False
                elif event.button == 1:
                    if contains(circle,event.pos):
                        circle["color"]=get_random_color()
                    return True
    return True

def main():
    clock = pygame.time.Clock()
    screen = init()
    running = True
    circle = get_circle_dict(300, 200, 50, get_random_color(),0,0)
    while running:
        screen.fill(LIGHTGREY)
        draw_circle(screen, circle)
        pygame.display.flip()
        running  = handle_events(screen, circle)
        clock.tick(60)
    pygame.quit()

main()

Kreise mit Klick entfernen

Jetzt soll ein Programm entwickelt werden, das auf der Zeichenfläche 10 Zufallskreise erzeugt, die nacheinander per Mausklick gelöscht werden können. Die Kreise erzeugen wir wieder mit einer leicht veränderten Funktion get_random_circle_list(n), die du bereits in Programm 6 kennengelernt hast..

def get_random_circle_list(n):
    circle_list = []
    for _ in range(n):
        radius = random.randint(10, 20)
        x = random.randint(radius, WIDTH - radius)
        y = random.randint(radius, HEIGHT - radius)
        dx =0
        dy = 0
        col = (random.randint(0, 255),random.randint(0, 255),random.randint(0, 255))
        circle_list.append(get_circle_dict(x, y, radius, col, dx, dy ))
    return circle_list

Im Gegensatz zu Programm 6 haben wir die Bewegunngsdistanzen dx und dy auf 0 gesetzt, da sich die Kreise in diesem Programm nicht bewegen sollen.

In der main-Funktion des letzten Beispiels müssen wir die Anweisung, die das Circle-Dictionary erzeugt durch circlelist = get_random_circle_list(10) eresetzen und den Aufruf draw_circle durch eine Schleife, die die circle_list durchläuft und jeden der Kreise zeichnet. An die Paramter der Funktion handle_events-Funktion übergeben wir die Variablen screen und circle_list . Damit ergibt sich folgende main-Funktion:

def main():
    clock = pygame.time.Clock()
    screen = init()
    running = True
    circle_list = get_random_circle_list(10)
    while running:
        screen.fill(LIGHTGREY)
        for circle in circle_list:
            draw_circle(screen, circle)
        running, circle_list = handle_events(screen, circle_list)
        pygame.display.flip()
        clock.tick(60)
    pygame.quit()

Um die Kreise per Mausklick entfernen zu können, müssen wir die Funktion handle_events überarbeiten. Wir übergeben screen und die Liste circle_list der Kreise als Parameter an die Funktion. Bei einem Klick mit der linken Maustaste durchlaufen wir die Liste der Kreise und entfernen den Kreis aus der Liste, auf den geklickt wurde. Dazu benötigen wir wieder die im letzten Beispiel entwickelte Funktoin contains(c, p). Da sich die Kreisliste in handle_events verändert, übergeben wird diese wieder zurück an die main-Funktion. Damit ergeben sich folgende Funktionen.

def contains(c, pos):
    if math.hypot(pos[0] -c["x"], pos[1] - c["y"]) < c["radius"]:
        return True
    return False

def handle_events(cl, screen):
    for event in pygame.event.get():
         if event.type == pygame.MOUSEBUTTONDOWN:
            if event.button == 3: # Rechte Maustaste
                return False, cl
            elif event.button == 1:
                for circle in cl
                    if contains(circle, event.pos):
                        c.remove(circle)
                return True, cl
    return True, cl

 

Icon Aufgabe 30x30 Auftrag   

Implementiere mithilfe der entwickelten Funktionen das vollständige Programm und teste es. Acht auf den Import der richtigen Bibliotheken.

Programm 9
import pygame
import random
import math

WIDTH = 650
HEIGHT = 450
BLUE = (0, 0, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
LIGHTGREY = (240, 240, 240)


def init():
    pygame.init()
    screen = pygame.display.set_mode((WIDTH, HEIGHT))
    screen.fill(LIGHTGREY) 
    pygame.display.flip()
    return screen

def random_color():
    return (random.randint(0,255),random.randint(0,255),random.randint(0,255))

def get_circle_dict(x, y, r, col, dx, dy):
    return {"x":x, "y":y, "radius": r, "color":col,"dx":dx, "dy":dy}

def draw_circle(screen,c):
     pygame.draw.circle(screen, c["color"], ( c["x"],c["y"]), c["radius"])

def get_random_circle_list(n):
    circle_list = []
    for _ in range(n):
        radius = random.randint(10, 20)
        x = random.randint(radius, WIDTH - radius)
        y = random.randint(radius, HEIGHT - radius)
        dx = random.randint(-2,2)
        if dx == 0:
            dx = dx + 1
        dy = random.randint(-2,2)
        if dy == 0:
            dy = dy - 1
        col = (random.randint(0, 255),random.randint(0, 255),random.randint(0, 255))
        circle_list.append(get_circle_dict(x, y, radius, col, dx, dy ))
    return circle_list

def contains(c, pos):
    if math.hypot(pos[0] -c["x"], pos[1] - c["y"]) < c["radius"]:
        return True
    return False

def handle_events(screen, cl):
    for event in pygame.event.get():
        if event.type == pygame.MOUSEBUTTONDOWN:
                if event.button == 3:  # Rechte Maustaste
                    return False
                elif event.button == 1: #linke Maustaste
                    for circle in cl:
                        if contains(circle, event.pos):
                             cl.remove(circle)
                    return True, cl
    return True, cl

def main():
    clock = pygame.time.Clock()
    screen = init()
    running = True
    circle_list = get_random_circle_list(10)
    while running:
        screen.fill(LIGHTGREY)
        for circle in circle_list:
            draw_circle(screen, circle)
        pygame.display.flip()
        running, circle_list  = handle_events(screen, circle_list)
 
        clock.tick(60)
    pygame.quit()

main()
 

Icon Aufgabe 30x30 Auftrag  

Bearbeite von Aufgaben 2 nun die erste Aufgabe

Kreis verschieben

In diesem Abschnitt beschäftigen wir uns mit mit dem Mousevent MOUSEMOTION, das ausgelöst wird,  wenn die Maus bewegt wird, egal ob eine Maustaste gedrückt ist oder nicht.. Im ersten Beispiel erläutern wir ein Programm, mit dem ein Kreis im Grafikfenster mit der Maus bewegt werden kann, wenn die linke Maustaste gedrückt ist.

Programm 10

import pygame

WIDTH = 650
HEIGHT = 450
WHITE = (255, 255, 255)
BLACK = (0, 0, 0, 0)
RED = (255, 0, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
LIGHTGREY = (240, 240, 240)

def init():
    pygame.init()
    screen = pygame.display.set_mode((600, 400))
    screen.fill(LIGHTGREY)
    return screen

def get_circle_dict(x, y, r, col, dx, dy):
    return {"x":x, "y":y, "radius": r, "color":col,"dx":dx, "dy":dy}

def draw_circle(screen,c):
    pygame.draw.circle(screen, c["color"], ( c["x"],c["y"]), c["radius"])

def handle_events(circle, dragging):
    for event in pygame.event.get():
        if event.type == pygame.MOUSEBUTTONDOWN:
            if event.button == 1:
                dragging = True
            elif event.button == 3:
                return False, dragging, circle
        elif event.type == pygame.MOUSEBUTTONUP:
            if event.button == 1:
                dragging = False
        elif event.type == pygame.MOUSEMOTION and dragging:
            circle["x"], circle["y"] = event.pos
    return True, dragging, circle

def main():
    screen = init()
    clock = pygame.time.Clock()
    circle = get_circle_dict(320, 240, 30, BLUE, 0, 0)
    running = True
    dragging = False
    while running:
        screen.fill(LIGHTGREY)
        draw_circle(screen, circle)
        pygame.display.flip()
        running, dragging, circle = handle_events(circle, dragging)
        clock.tick(60)

main()

Erläuterung

In der main-Funktion erzeugen wir wieder ein Circle-Dictionary, das in der Programm-Schleife immer wieder in das gelöschte Grafikfenster gezeichnet wird. Zusätzlich haben wir eine Variable dragging die die Werte True und False annehmen kann. Wenn dragging True ist, befindet sich die Maus im "Ziehmodus", d.h. die Maustaste ist gedrückt und bei einer Bewegung wird der Kreis im Grafikfenster so bewegt, dass der Mittelpunkt auf die aktuelle Mausposition verschoben wird. Dragging wir in der Funktion handle-events gesetzt und von ihr zurückgegeben. In der folgenden Tabelle erläutern wir handle_events zeilenweise.

 

Zeile Erläuterung
24 Die Event-Handler-Funktion wird mit zwei Parametern: circle (Kreis-Objekt) und dragging (Drag-Status) deklariert. dragging ist True, wenn die linke Maustaste gedrückt ist.
25 Mit pygame.event.get() wird die Liste aller Ereignisse (Events) abgefragt, die seit dem letzten Aufruf aufgetreten sind. Diese werden in einer Schleife einzeln durchlaufen.
26 Es wird geprüft, ob es sich bei dem aktuellen Event um ein Maustastendruck-Ereignis (MOUSEBUTTONDOWN) handelt.
27 Es wird geprüft, ob die linke Maustaste gedrückt wurde (Button 1 = links, 2 = mittel, 3 = rechts)
28 dragging wir auf True gesetzt - der Kreis kann jetzt mit der Maus bewegt werden
29 Prüft, ob die rechte Maustaste gedrückt wurde.
30 Die Funktion wird beendet mit der Rückgabe von False, damit das Programm beendet wird. Die Rückgabe von dragging und circle spielt für den Programmablauf keine Rolle, muss aber erfolgen, da in main drei Rückgabewerte erwartet werden.
31 Es wird geprüft, ob eine Maustaste losgelassen wurde
32 dragging wird auf False gesetzt, wenn die linke Maustaste losgelassen wird
33 Prüft, ob sich die Maus bewegt UND dragging den Wert True hat ist
34 Setzt die Position des Kreises auf die aktuelle Mausposition (event.pos ist ein (x,y)-Tupel)
35 Gibt drei Werte zurück, weil sie u.U verändert wurden:True (Programm soll fortgesetzt werden) ,dragging (aktueller Drag-Status) und circle evtl. mit neuen Koordinaten.

 

Icon Aufgabe 30x30 Auftrag  

Bearbeite von Aufgaben 2 nun die Aufgaben 2 und 3

Malen mit der Maus

Als zweite Anwendung für das MOUSEMOTION-Event entwickeln wir ein Programm, mit dem man mit der Maus oder mit dem Finger auf dem Tablet malen kann. Bevor wir das Programm zeigen, müssen wir noch erklären, was das "Nichts" in Python ist.

None

None ist ein spezieller Wert in Python, der bedeutet: "Hier ist nichts" oder "Dieser Platz ist leer". Man verwendet ihn z.B., wenn man eine Variable deklarieren will, ohne ihr sofort einen Wert zuzuweisen.  Mit if Variablenname: liefert True, wenn die Variable einen Wert hat und False, wenn die Variable noch keinen Wert hat also auf None gssetzt wurde. Funktionen können den Wert None zurückgeben.

Beispiele
zahl = None
if !zahl:
    print("Die zahl hat noch keinen Wert")
else:
    print("Die Zahlen hat einen Wert")

def suche_schluessel():
    # Schauen wir in der Tasche nach...
    if schluessel_gefunden:
        return"Schlüssel"
    else
       return None # "Nichts gefunden"


Das nebenstehende Video zeigt ein (zugegeben sehr einfaches) Beispiel für die Ausführung des Malprogramms.

Der Algorithmus läuft nach folgendem Prinzip ab. Sobald die linke Maustaste gedrückt wird, wird in der Funktion handle_events die Mausposition in einer Variablen from_pos gespeichert und die Varaible dragging auf True gesetzt. Bei jeder Mausbewegung wird die Mausposition in der Variablen to_pos gespeichert.  Der Drag-Status sowie die Anfangs- und Endposition werden sofort von der Funktion handle_events an die main-Funktion zurückgegeben. Wenn dragging gleich True ist und from_pos und to_pos nicht None sind,  zeichnet diese eine Linie zwischen den beiden Punkten. Da die Endposition der Linie die neue Anfangsposition ist, erhölt from_pos den Wert von to_pos. Wenn die linke Maustaste losgelassen wird, wird drawing auf False gesetzt und es wird bei einer Mausbewegung nicht mehr gezeichnet. Die Variable drawing wird zu Beginn des Programms mit False, from_pos und to_pos werden mit None initialisiert.

Daraus ergibt sich folgendes Python-Programm:

Programm 11

import pygame

WIDTH = 650
HEIGHT = 450
WHITE = (255, 255, 255)
RED = (255, 0, 0)
LIGHTGREY = (240, 240, 240)

def init():
    pygame.init()
    screen = pygame.display.set_mode((WIDTH, HEIGHT))
    screen.fill(LIGHTGREY)
    pygame.display.flip()
    return screen

def draw_line(screen, start_pos, end_pos):
    pygame.draw.line(screen, RED, start_pos, end_pos, 3)

def handle_events(drawing, from_pos):
    for event in pygame.event.get():
        if event.type == pygame.MOUSEBUTTONDOWN:
            if event.button == 1:  # Linke Maustaste
                drawing = True
                from_pos = event.pos
            elif event.button == 3:  # Rechte Maustaste
                return False, drawing, from_pos, None
        elif event.type == pygame.MOUSEBUTTONUP:
            if event.button == 1:
                drawing = False
                from_pos = None  # Wichtig: Zurücksetzen beim Stoppen
        elif event.type == pygame.MOUSEMOTION and drawing:
            # Aktuelle Position für das Zeichnen zurückgeben
            return True, drawing, from_pos, event.pos
    return True, drawing, from_pos, None


def main():
    global screen
    clock = pygame.time.Clock()
    screen = init()
    drawing = False
    from_pos = None
    to_pos = None
    running = True
    
    while running:
        # Zeichnen nur in main - nur wenn beide Positionen gültig sind und drawing = True
        if drawing and from_pos and to_pos and from_pos != to_pos:
            draw_line(screen, from_pos, to_pos)
            from_pos = to_pos
        pygame.display.flip()
        running, drawing, from_pos, to_pos = handle_events(drawing, from_pos)
        clock.tick(60)
    pygame.quit()

main()

Buttons

Unser Malprogramm ist sehr einfach und wir wollen es jetzt verbessern, indem wir verschiedene Buttons hinzufügen, mit denen wir die Zeichnung löschen können und verschiedene Farben zum Zeichnen auswählen können. Zunächst erläutern wir, was ein Button ist und welche Eigenschaften ein Button hat.

Button in Pygame

Ein Button (auch Schaltfläche genannt) ist ein interaktives Element in der Benutzeroberfläche, das Benutzer anklicken können, um eine Aktion auszulösen. Buttons können verschiedene Formen haben, z.B. Rechtecke mit Aufschrift, Kreise oder irgendwelche Grafiksymbole.In vielen Programmiersprachen kann man einen Button durch eine einfache Anweisung in die Benutzeroberfläche einfügen. In Pygame müssen wir Buttons selbst programmieren. Wir beschränken uns auf rechteckige, farbige Buttons mit folgenden Eigenschaften (in der Fachsprache Attribute genannt) .

Attribut Beschreibung Beispiel
rect Das Rechteck, das dem Button die Form gibt button_rect = pygame.Rect(x, y, width, height)
color Farbe des Buttons als RGB-Tupel (255, 255, 255)
text Aufschrift "Löschen"

Darüber hinaus müssen wir eine Funktion deklarieren, die beim Klick auf den Button aufgerufen wird.

Zunächst erweitern wir unser Malprogramm um einen Button, mit dem die Zeichnung wieder gelöscht werden kann. Dazu deklarieren wir weitere Funktionen.

def get_button(x, y, w, h, c, t):
    return {"rect":pygame.Rect(x, y, w, h),"color":c, "text":t}

def draw_button(screen, button):
    # Button-Rechteck zeichnen
    pygame.draw.rect(screen, button["color"], button["rect"])
    # Button-Text zeichnen
    font = pygame.font.Font(None, 24)
    text = font.render(button["text"], True, WHITE)
    text_rect = text.get_rect(center=button["rect"].center)
    screen.blit(text, text_rect)

def is_button_clicked(pos, button):
    """Prüft, ob der Button geklickt wurde"""
    return button["rect"].collidepoint(pos)

def clear_screen(screen):
    screen.fill(LIGHTGREY)

Die Funktion get_button(x, y, w, h, c, t) gibt uns ein Button-Objekt als Dictionary zurück. Als Parameter übergeben wir die x- und y-Poition der linken oberen Ecke des Button-Rechtecks sowie dessen Breite und Höhe. Der Parameter c bekommt die Hintergrundfarbe des Buttons zugewiesen und t den Text, mit dem der Button beschriftet wird.

Die Funktion def draw_button(screen, button) zeichnet den Button. Als Parameter werden die Zeichenfläche und das Button-Dictionary übergeben.

Die Funktion def is_button_clicked(pos, button) prüft, ob der Punkt pos, also in der Regel die Klickposition der Maus, innerhalb des buttons liegt. Zurückgegeben werden True oder False. Dazu wird die  Methode colloidepoint verwendet, die eine Methode von Rect - Objekten ist.

Die Funktion def clear_screen(screen) löscht den Bildschirm.

Jetzt müssen wir noch die Funktionen handle_events und main erweitern.

def handle_events(drawing, from_pos, button):
    for event in pygame.event.get():
        if event.type == pygame.MOUSEBUTTONDOWN:
            if event.button == 1: # Linke Maustaste
                # Prüfe zuerst, ob Button geklickt wurde
                if is_button_clicked(event.pos, button):
                    drawing = False
                    return True, None, None, None, button
                else:
                   # Normales Zeichnen
                   drawing = True
                   from_pos = event.pos
            elif event.button == 3: # Rechte Maustaste
                return False, None,None, None, None
        elif event.type == pygame.MOUSEBUTTONUP:
             if event.button == 1:
                 drawing = False
                 from_pos = None # Wichtig: Zurücksetzen wenn Maustaste losgelassen
        elif event.type == pygame.MOUSEMOTION and drawing:
             # Aktuelle Position für das Zeichnen zurückgeben
             return True, drawing, from_pos, event.pos, None
    return True, drawing, from_pos, None, None

 

Zeile Erläuterung
1 Die handle_events-Funktion benötigt die drei Parameter drawing, from_pos und button, die unter Umständen verändert an main zurückgegeben werden. Insgesamt werden beim Beenden der Funktion fünf Parameter zurückgegeben und den Variablen running, drawing, from_pos, to_pos, button zugewiesen. Wenn eine Variable für das jeweilige Event nicht relevant ist, wird stattdessen None zurückgegeben.
4 Wenn die linke Maustaste gedrückt wurde, müssen wir zwei Fälle unterscheiden.
6 - 8 1. Fall: Ein Button wurde gedrückt. In diesem Fall muss drawing auf False gesetzt werden und drawing und button werden zurückgegeben. In weiteren Versionen des Programms werden wir mehrere Buttons haben, die als Liste an handle_events übergeben werden. In diesem Fall wird der Button zurückgegeben, der geklickt wurde.
13 -14 Die rechte Maustaste wurde gedrückt und für running wird False zurückgegeben.
15 - 18 Die rechte Maustaste wurde losgelassen, das heißt, dass nicht weiter gezeichnet werden soll. Daher müssen drawing auf False und from_pos auf None gesetzt werden. 
19 - 21 Die Maus wurde bewegt und es soll gezeichnet werden. Daher wird die Funktion beendet und die aktuelle Mausposition an to_pos zurückgegeben.
22 Diese return-Anweisung wird nur erreicht, wenn entweder die linke Maustaste in der Zeichenfläche geklickt wurde oder die Event-Schleife leer ist. Da im ersten Fall drawing und from_pos verändert wurden, müssen Werte für running, drawing und from_pos zurückgegeben werden.

Jetzt fehlt nur noch die main-Funktion

def main():
    clock = pygame.time.Clock()
    screen = init()
    clear = clear_screen(screen)
    del_button = get_button(5, HEIGHT - 35, 100, 30, BLUE, "Löschen")
    draw_button(screen, del_button)
    drawing = False
    from_pos = None
    to_pos = None
    running = True
    while running:
        # Events verarbeiten
        running, drawing, from_pos, to_pos, button = handle_events(drawing, from_pos, del_button)
        if button:
            # Button wurde geklickt - Bildschirm löschen
            clear_screen(screen)
            draw_button(screen, del_button) # Button neu zeichnen
        elif drawing and from_pos and to_pos and from_pos != to_pos:
            draw_line(screen, from_pos, to_pos)
            from_pos = to_pos
    pygame.display.flip()
    clock.tick(60)
    pygame.quit()

Wir erläutern die Zeilen der Funktion, die dem Malprogramm hinzugefügt wurden, um den Lösch-Button zu implementieren.

 

Zeile Erläuterung
5 Der Löschbutton wird erzeugt
6 Der Löschbutton wird gezeichnet.
15 Es wird geprüft ob handle-events einen Button zurückgegeben hat und nicht None ist.
17 Wenn der Button zurückgegeben wurde, wird die Zeichenfläche gelöscht.
18 Der Button wird neue gezeichnet.

Jetzt erweitern wir das Programm noch um drei Buttons, mit denen wir die Malfarbe(rot, grün, blau) wählen können. Diese speichern wir in der Liste buttons.  Die aktuelle Malfarbe speichern wir in draw_color und zeigen sie durch einen kleinen Kreis chosen_color,rechts unten in der Zeichenfläche an.

draw_color = RED
chosen_color = get_circle_dict(WIDTH-15, HEIGHT - 15, 10, RED)
buttons = []
buttons.append(get_button(5, HEIGHT - 35, 100, 30, BLUE, "Löschen"))
buttons.append(get_button(115, HEIGHT - 35, 50, 30, DARKGREEN, ""))
buttons.append(get_button(175, HEIGHT - 35, 50, 30, BLUE, ""))
buttons.append(get_button(235, HEIGHT - 35, 50, 30, RED, ""))
draw_buttons(screen, buttons)

Der handle_events-Funktion übergeben wir als Parameter jetzt die Liste mit den Buttons. Wenn ein Button gedrückt wurde, gibt die Event-Funktion den geklickten Button zurück.

def handle_events(drawing, from_pos, buttons):
    for event in pygame.event.get():
        if event.type == pygame.MOUSEBUTTONDOWN:
            if event.button == 1: # Linke Maustaste
                # Prüfe zuerst, ob Button geklickt wurde
                 for button in buttons:
                     if is_button_clicked(event.pos, button):
                         drawing = False
                         returnTrue, drawing, None, None, button
                     else:
                         # No.rmales Zeichnen
                         drawing = True
                         from_pos = event.pos
            elif event.button == 3: # Rechte Maustaste
                returnFalse, None, None, None, None
            elif event.type == pygame.MOUSEBUTTONUP:
                if event.button == 1:
                    drawing = False
                    from_pos = None # Wichtig: Reset beim Stoppen
                    returnTrue, drawing, from_pos, None, None
            elif event.type == pygame.MOUSEMOTION and drawing:
                # Aktuelle Position für das Zeichnen zurückgeben
                returnTrue, drawing, from_pos, event.pos, None
    return True, drawing, from_pos, None, None

Die Verarbeitung in der main-Funktion findest du im folgenden Programmausschnitt. 

while running:
    # Events verarbeiten
    running, drawing, from_pos, to_pos, button = handle_events(drawing, from_pos, buttons)
    draw_circle(screen, chosen_color)
    if button:
        # Button wurde geklickt - Bildschirm löschen
            if button["text"]=="": #Es ist ein Farbbutton
                draw_color = get_color(button["color"])
                chosen_color["color"]=button["color"]
            else:
                clear_screen(screen)
                draw_buttons(screen, buttons) # Button neu zeichnen
                drawing = False
                from_pos = None
    elif drawing and from_pos and to_pos and from_pos != to_pos:
        draw_line(screen, from_pos, to_pos, draw_color)
        from_pos = to_pos
    pygame.display.flip(
    clock.tick(60))

Wenn du jetzt noch die Funktion draw_buttons hinzufügst, hast du das Programm fertiggestellt.

Icon Aufgabe 30x30  Auftrag

Versuche nun, das Mal-Programm mit Lösch- und Farbbuttons mithilfe der erläuterten Erweiterungen selbstständig in WTP zu implementieren.

Programm 12
import pygame

# Konstanten
WIDTH = 650
HEIGHT = 500  # Höher für Button-Bereich
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
LIGHTGREY = (240, 240, 240)
BLACK = (0, 0, 0)
BLUE = (0, 0, 255)
DARKGREEN = (34, 139, 34)

def init():
    pygame.init()
    screen = pygame.display.set_mode((WIDTH, HEIGHT))
    screen.fill(LIGHTGREY)
    pygame.display.flip()
    return screen

def get_button(x, y, w, h, c, t):
    return {"rect":pygame.Rect(x, y, w, h),"color":c, "text":t}

def get_circle_dict(x, y, r, col):
    return {"x":x, "y":y, "radius": r, "color":col}

def draw_circle(screen,c):
   pygame.draw.circle(screen, c["color"], ( c["x"],c["y"]), c["radius"])

def draw_buttons(screen, buttons):
    """Zeichnet den Löschen-Button"""
    # Button-Rechteck zeichnen
    for button in buttons:
        pygame.draw.rect(screen, button["color"], button["rect"])
    
        # Button-Text zeichnen mit expliziter weißer Farbe
        font = pygame.font.Font(None, 24)
        text_color = (255, 255, 255)  # Explizit weiß
        text = font.render(button["text"], True, text_color)
    
        # Text-Position berechnen
        text_rect = text.get_rect()
        text_rect.center = button["rect"].center
    
    # Text zeichnen
        screen.blit(text, text_rect)


def is_button_clicked(pos, button):
    #Prüft, ob der Button geklickt wurde
    return button["rect"].collidepoint(pos)

def handle_events(drawing, from_pos, buttons):
    for event in pygame.event.get():
        if event.type == pygame.MOUSEBUTTONDOWN:
            if event.button == 1: # Linke Maustaste
                # Prüfe zuerst, ob Button geklickt wurde
                for button in buttons:
                    if is_button_clicked(event.pos, button):
                        drawing = False
                        return True, drawing, None, None, button
                else:
                   # Normales Zeichnen
                   drawing = True
                   from_pos = event.pos
            elif event.button == 3: # Rechte Maustaste
                return False, None, None, None, None
        elif event.type == pygame.MOUSEBUTTONUP:
            if event.button == 1:
                drawing = False
                from_pos = None # Wichtig: Reset beim Stoppen
                return True, drawing, from_pos, None, None
        elif event.type == pygame.MOUSEMOTION and drawing:
                # Aktuelle Position für das Zeichnen zurückgeben
                return True, drawing, from_pos, event.pos, None
    return True, drawing, from_pos, None, None

def draw_line(screen, start_pos, end_pos, color):
    pygame.draw.line(screen, color, start_pos, end_pos, 3)


def clear_screen(screen):
    screen.fill(LIGHTGREY)

def get_color(color):
    return color

def main():
    clock = pygame.time.Clock()
    screen = init()
    draw_color = RED
    chosen_color = get_circle_dict(WIDTH-15, HEIGHT - 15, 10, RED)
    buttons = []
    buttons.append(get_button(5, HEIGHT - 35, 100, 30, BLUE, "Löschen"))
    buttons.append(get_button(115, HEIGHT - 35, 50, 30, DARKGREEN, ""))
    buttons.append(get_button(175, HEIGHT - 35, 50, 30, BLUE, ""))
    buttons.append(get_button(235, HEIGHT - 35, 50, 30, RED, ""))
    draw_buttons(screen, buttons)
    drawing = False
    from_pos = None
    to_pos = None
    running = True
    pygame.display.flip()
    
    while running:
        # Events verarbeiten
        running, drawing, from_pos, to_pos, button = handle_events(drawing, from_pos, buttons)
        draw_circle(screen, chosen_color)
        if button:
            # Button wurde geklickt - Bildschirm löschen
            if button["text"]=="":
                draw_color = get_color(button["color"])
                chosen_color["color"]=button["color"]
            else:
                clear_screen(screen)
            draw_buttons(screen, buttons)  # Button neu zeichnen
            drawing = False
            from_pos = None
        elif drawing and from_pos and to_pos and from_pos != to_pos:
            draw_line(screen, from_pos, to_pos, draw_color)
            from_pos = to_pos
        pygame.display.flip()
        
        clock.tick(60)
    pygame.quit()

main() 

Icon Aufgabe 30x30  Auftrag

Bearbeite jetzt die Aufgaben 4 bis 6 von Aufgaben 2

Wichtiger Hinweis: Wenn du WebTigerPython auf einem Tablet nutzt, kannst du die folgenden Programme nur dann ausführen, wenn du eine externe Tastatur angeschlossen hast. Mit der virtuellen Tastatur funkioniert es nicht.

Key-Events

 KeyEvents sind Ereignisse, die auftreten, wenn der Benutzer eine Taste auf der Tastatur drückt oder loslässt. In Pygame können wir diese Events abfangen und darauf reagieren.

Wichtig in Pygame sind Key-Events bei Spielen, die mit der Tastatur bedient werden. Wenn event.type den Wert pygame.KEYDOWN (Tastegedrückt) oder pygame.KEYUP (Taste losgelassen) hat, ist ein Tastaturevent eingetreten. Mit event.key kann man die Taste abfragen, die gedrückt wurde.

Beispiel 1

def handle_events(): 
    for event in pygame.event.get(): 
        if event.type == pygame.KEYDOWN: 
            if event.key == pygame.K_ESCAPE: 
                return False # Programm beenden 
    return True

Erläuterung

 Das Pygame-Programm wird beendet,wenn auf dem PC die Escape-Taste gedrückt wurde.

Tastencodes

Taste Code
Navigationstasten
 → pygame.K_RIGHT
pygame.K_LEFT
pygame.KEY_UP
pygame.KEY_DOWN
Buchstaben, Ziffern
a ... z pygame.KEY_a ... pygame.KEY_z
0 ... 9  pygame.K_0 ... pygame.K_9
Funktionstasten
 esc  pygame.K_ESCAPE
↵   pygame.K_RETURN
" "
Leerzeichen
pygame.K_SPACE

Beispiel 2

Mit folgendem Programm  kann man einen Kreis mit den Pfeiltasten auf dem Blidschirm bewegen und mit den Tasten r,  g , b die Farbe des Kreises in rot, grün oder blau ändern.

import pygame

WIDTH = 650
HEIGHT = 450
WHITE = (255, 255, 255)
BLACK = (0, 0, 0, 0)
RED = (255, 0, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
LIGHTGREY = (240, 240, 240)


def init():
    pygame.init()
    screen = pygame.display.set_mode((WIDTH, HEIGHT))
    screen.fill(LIGHTGREY)  # Schwarzer Hintergrund
    pygame.display.flip()
    return screen

def draw_circle(screen,x, y, r, color): 
 pygame.draw.circle(screen, color,  (x,y), r)

 
def edge_left_right(x, r):
    if x + r > WIDTH or x - r < 0:
  r      return True
    return False


def handle_events():
    for event in pygame.event.get():
 g       if event.type == pygame.MOUSEBUTTONDOWN:
                if event.button == 3:  # Rechte Maustaste
                    return False, None
        if event.type == pygame.KEYDOWN:
            return True, event.key
    return True, None
b
def main():
    clock = pygame.time.Clock()
    screen = init()
    x, y = 200, 300
    radius = 30
    color = RED
    dx = 5
    dy = 5
    running = True
    
    while running:
        screen.fill(LIGHTGREY)  
        draw_circle(screen,x, y, radius, color)
        running,key = handle_events()
        if key == pygame.K_RIGHT:
            x = x + dx
        elif key == pygame.K_LEFT:
            x = x - dx
        elif key == pygame.K_UP:
            y = y - dy
        elif key == pygame.K_DOWN:
            y = y + dy
        elif key == pygame.K_r:
            color = RED
        elif key == pygame.K_g:
            color = GREEN
        elif key == pygame.K_b:
            color = BLUE
        pygame.display.flip()
        clock.tick(60)
    pygame.quit()

main()

 

Wenn du das Programm testest, merkst du schnell: Es ist nervig! 🥴

Du kannst den Ball zwar mit den Pfeiltasten bewegen, aber du musst ständig die Tasten drücken und loslassen.

Wir erweitern das Programm jetzt so, dass der Ball sich automatisch weiterbewegt, solange du eine Taste gedrückt hältst - wie bei einem Auto mit eingeschaltetem Motor! 🏎️

Um das zu erreichen müssen wir wissen, ob eine Pfeiltaste gedrückt ist. Dies speichern wir in einer Variablen. Sobald die Taste wieder losgelassen wird, wird der Wert der Variablen auf False gesetzt.  Dies gilt für alle Tasten, die wir im Programm benutzen. Wir verwenden dahe ein Dictionary mit den verwendeten Tasten als key und True oder False als Wert. In der main-Funktion initialisieren wir die Variable key_pressed folgendermaßen:

keys_pressed = {pygame.K_RIGHT:False, pygame.K_LEFT:False, pygame.K_UP:False,pygame.K_DOWN:False, pygame.K_r:False,pygame.K_b:False, pygame.K_g:False}

Wir setzen alle Werte auf False, weil beim Programmstart noch keine Taste gedrückt wurde. In der Funktion handle_events, wird der Wert der gedrückten Taste auf True gesetzt und beim Loslassen wieder auf False. Die Variable keys_pressed müssen wir an handle_events übergeben und auch wieder zurückgeben, weil sich der Wert verändern kann.

Damit ergibt sich folgende Funktion:

def handle_events(keys_pressed):
     for event in pygame.event.get():
        if event.type == pygame.MOUSEBUTTONDOWN:
            if event.button == 3: # Rechte Maustaste
                return False, keys_pressed
        elif event.type == pygame.KEYDOWN:
            keys_pressed[event.key] = True
            return True, keys_pressed
        elif event.type == pygame.KEYUP:
            keys_pressed[event.key] = False
            return True, keys_pressed
    return True, keys_pressed

 Für die Bewegung des Kreises schreiben wir eine eigene Funktion:

def move_circle(keys_pressed,x, y, dx, dy):
    if keys_pressed[pygame.K_RIGHT]:
        x = x + dx
    elif keys_pressed[pygame.K_LEFT]:
        x = x - dx
    elif keys_pressed[pygame.K_UP]:
        y = y - dy
    elif keys_pressed[pygame.K_DOWN]:
        y = y + dy
 return x, y

 

Icon Aufgabe 30x30 Auftrag  

Vervollständige das Programm unter Verwendung des erarbeiteten Codes.

import pygame

WIDTH = 650
HEIGHT = 450
WHITE = (255, 255, 255)
BLACK = (0, 0, 0, 0)
RED = (255, 0, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
LIGHTGREY = (240, 240, 240)


def init():
    pygame.init()
    screen = pygame.display.set_mode((WIDTH, HEIGHT))
    screen.fill(LIGHTGREY)  # Schwarzer Hintergrund
    pygame.display.flip()
    pygame.key.set_repeat()
    return screen

def draw_circle(screen,x, y, r, color): 
    pygame.draw.circle(screen, color,  (x,y), r)


def handle_events(keys_pressed):
    for event in pygame.event.get():
        if event.type == pygame.MOUSEBUTTONDOWN:
            if event.button == 3:  # Rechte Maustaste
                return False, keys_pressed
        if event.type == pygame.KEYDOWN:
            keys_pressed[event.key] = True
            return True, keys_pressed
        if event.type == pygame.KEYUP:
            keys_pressed[event.key] = False
            return True, keys_pressed
    return True, keys_pressed

def move_circle(keys_pressed,x, y, dx, dy):
        if keys_pressed[pygame.K_RIGHT]:
            x = x + dx
        elif keys_pressed[pygame.K_LEFT]:
            x = x - dx
        elif keys_pressed[pygame.K_UP]:
            y = y - dy
        elif keys_pressed[pygame.K_DOWN]:
            y = y + dy
        return x, y

def main():
    clock = pygame.time.Clock()
    screen = init()
    x, y = 200, 300
    radius = 30
    color = RED
    dx = 5
    dy = 5
    running = True
    keys_pressed = {pygame.K_RIGHT:False, pygame.K_LEFT:False, pygame.K_UP:False,pygame.K_DOWN:False, pygame.K_r:False,pygame.K_b:False, pygame.K_g:False}
    
    while running:
        screen.fill(LIGHTGREY)  
       
        draw_circle(screen,x, y, radius, color)
        running,keys_pressed = handle_events(keys_pressed)
        x, y = move_circle(keys_pressed, x, y, dx, dy)
        if keys_pressed[pygame.K_r]:
            color = RED
        elif keys_pressed[pygame.K_g]:
            color = GREEN
        elif keys_pressed[pygame.K_b]:
            color = BLUE
        pygame.display.flip()
        clock.tick(60)
    pygame.quit()

main()
 

Impressum
© 2023  Net-Schulbuch.de

10.07  0.5888  8.1.33