DGHK Ostercamp 2024 : Python

„Fenster, Knöpfe, Schieberegler und Grafikeffekte unter Python“

1. Python Crashkurs Beispiele

Download aller Beispele

1.1 Variablen

anzahl_kekse = 123
preis_pro_keks = 1.20
kosten = anzahl_kekse * preis_pro_keks
print(kosten)
# => 147.6

1.2 Listen

sachen = ["buch", "brille", "kekse"]
print(sachen)
# => ['buch', 'brille', 'kekse']

erste_sache = sachen[0]
print(erste_sache)
# => buch

dritte_sache = sachen[2]
print(dritte_sache)
# => kekse

vierte_sache = sachen[3]
print(vierte_sache)
# => IndexError: list index out of range

sachen.append("saft")
vierte_sache = sachen[3]
print(vierte_sache)
# => saft

1.3 Dictionaries

person = { "name": "Maria",
           "alter": 15,
           "hobbies": ["Lesen", "Programmieren", "Tischtennis"] }

print(person)
# => {'name': 'Maria', 'alter': 15, 'hobbies': ['Lesen', 'Programmieren', 'Tischtennis']}

name = person["name"]
print(name)
# => Maria

alter = person["alter"]
print(alter)
# => 15

hobbies = person["hobbies"]
print(hobbies)
# => ['Lesen', 'Programmieren', 'Tischtennis']

person["wohnort"] = "Berlin"
wohnort = person["wohnort"]
print(wohnort)
# => Berlin

1.4 Funktionen

def addiere(a, b):
    return a + b

c = addiere(3, 4)
print(c)
# => 7

1.5 for-Schleifen

for zaehler in range(10):
    print(zaehler)
    # => zählt von 0 bis 9

obst = ["äpfel", "birnen", "bananen"]
for element in obst:
    print("ich mag", element)
    # => ich mag äpfel
    # => ich mag birnen
    # => ich mag bananen

1.6 while-Schleifen

while(True):
    print("Bitte gib etwas ein! Beenden mit 'ENDE'")
    eingabe = input()

    # Die Eingabe wird mit "ENDE" verglichen:
    if eingabe == "ENDE":
        # Wenn der Vergleich wahr ist, verlassen wir die Schleife:
        break

    print("Du hast", eingabe, "eingegeben!")

print("Das Programm ist vorbei")

1.7 Module

import random as rand

z1 = rand.random()
print(z1)
# => Zufallszahl zwischen 0 und 1

z2 = rand.randrange(10, 20)
print(z2)
# => Zufallszahl zwischen 10 und 19

2. PySimpleGUI Beispiele

Download

2.1 Das Minimalbeispiel

import PySimpleGUI as sg

sg.set_options(font=("Courier", 30))

layout = [
    [sg.Input(key="-EINGABE-")],
    [sg.Button("Übertragen", key="-UEBERTRAGEN-")],
    [sg.Input(key="-AUSGABE-", disabled=True)],
    [sg.Button("Beenden", key="-BEENDEN-")]
]

window = sg.Window("Minimalbeispiel",
                   layout,
                   size=(300, 250))

while True:
    event, values = window.read()

    if event == sg.WIN_CLOSED or event == "-BEENDEN-":
        break

    if event == "-UEBERTRAGEN-":
        text_eingabe = values["-EINGABE-"]
        window["-AUSGABE-"].update(text_eingabe)

window.close()

2.2 Das Minimalbeispiel, kommentiert

# Import des PySimpleGUI-Moduls unter dem Kürzel sg
import PySimpleGUI as sg

# Wir setzten die Option 'font' auf ("Courier", 30),
# damit die Schrift nicht so winzig ist!
sg.set_options(font=("Courier", 30))

# Das Layout ist eine zweidimensiopnale Tabelle!
# Jede Zeile der Tabelle ist eine Zeile im Layout!
# Das Schlüsselwortargument "key" legt den Namen des Elementes fest.
layout = [
    # Das Eingabefeld
    [sg.Input(key="-EINGABE-")],
    # Der Button "Übertragen"
    [sg.Button("Übertragen", key="-UEBERTRAGEN-")],
    # Das Ausgabefeld
    [sg.Input(key="-AUSGABE-", disabled=True)],
    # Der Button "Beenden"
    [sg.Button("Beenden", key="-BEENDEN-")]
]

# Hier erzeugen wir das Hauptfenster.
# Das zweite Argument ist immer das layout!
window = sg.Window("Minimalbeispiel",
                   layout,
                   size=(300, 250))

# Die Hauptschleife unseres Programms:
while True:
    # window.read() liefert das Event: welcher Knopf wurde gedrückt?
    # und values: ein Verzeichnis (genauer: Dictionary), das die Zustände
    # aller GUI Elemente enthält.
    event, values = window.read()

    # Wenn das Event sg.WIN_CLOSED war (das Hauptfenster wurde geschlossen)
    # oder der "Beenden"-Knopf gedrückt wurde...
    if event == sg.WIN_CLOSED or event == "-BEENDEN-":
        # springe aus der Hauptschleife
        break

    # Wenn der "Übertragen"-Knopf gedrückt wurde...
    if event == "-UEBERTRAGEN-":
        # wird der inhalt des Eingabefeldes kopiert...
        text_eingabe = values["-EINGABE-"]
        # und in das Ausgabefeld geschrieben
        window["-AUSGABE-"].update(text_eingabe)

# Diese Zeile wird nur erreicht, wenn die Hauptschleife verlassen wurde.
# Sie schließt das Hauptfenster, falls es nicht schon geschlossen ist:
window.close()

2.3 Das erweiterte Minimalbeispiel

import PySimpleGUI as sg

sg.set_options(font=("Courier", 30),
               background_color="yellow",
               element_background_color="#32CD32",
               button_color=('white', 'blue'))

layout = [
    [sg.Input(key="-EINGABE-")],
    [sg.Button("Übertragen", key="-UEBERTRAGEN-")],
    [sg.Button("Testknopf", key="-TEST-")],
    [sg.Combo(["Apfel", "Birne", "Banane"],
              default_value="Banane",
              enable_events=True,
              key="-AUSWAHL-")],

    [sg.Slider(range=(0, 255),
               default_value=128,
               orientation='h',
               enable_events=True,
               key="-REGLER-")],
    [sg.Input(key="-AUSGABE-", disabled=True)],
    [sg.Button("Beenden", key="-BEENDEN-")]
]

window = sg.Window("Minimalbeispiel",
                   layout,
                   size=(500, 450))

while True:
    event, values = window.read()
    # print("event:", event)
    # print("values:", values)
    
    if event == sg.WIN_CLOSED or event == "-BEENDEN-":
        break

    if event == "-UEBERTRAGEN-":
        text_eingabe = values["-EINGABE-"]
        window["-AUSGABE-"].update(text_eingabe)
        
    if event == "-TEST-":
        window["-AUSGABE-"].update("Testknopf gedrückt!")
        
    if event == "-AUSWAHL-":
        nachricht = values["-AUSWAHL-"] + " ausgewählt!"
        window["-AUSGABE-"].update(nachricht)
        
    if event == "-REGLER-":
        nachricht = "Regler: " + str(values["-REGLER-"])
        window["-AUSGABE-"].update(nachricht)

window.close()

2.4 Das erweiterte Minimalbeispiel, kommentiert

import PySimpleGUI as sg

sg.set_options(font=("Courier", 30),
               # Farbangaben per Html-Farbnamen oder im Hex-Code:
               background_color="yellow",
               element_background_color="#32CD32",
               # Button-Farben für gedrückt und losgelassen:
               button_color=('white', 'blue'))

layout = [
    [sg.Input(key="-EINGABE-")],
    [sg.Button("Übertragen", key="-UEBERTRAGEN-")],
    # NEU: Testknopf
    [sg.Button("Testknopf", key="-TEST-")],
    # NEU: Combo (=Drop-Down-Menü):
              # erstes Argument immer Liste mit Auswahlmöglichkeiten
    [sg.Combo(["Apfel", "Birne", "Banane"],
              # Standard Wert:
              default_value="Banane",
              # Die Liste soll Events erzeugen bei Nutzung:
              enable_events=True,
              key="-AUSWAHL-")],
    # NEU: Slider:
               # Wertebereich:
    [sg.Slider(range=(0, 255),
               # Standard Wert:
               default_value=128,
               # Ausrichtung 'h' oder 'v':
               orientation='h',
               # Events bei Nutzung:
               enable_events=True,
               key="-REGLER-")],
    # Alle Ausgaben landen hier:
    [sg.Input(key="-AUSGABE-", disabled=True)],
    [sg.Button("Beenden", key="-BEENDEN-")]
]

window = sg.Window("Minimalbeispiel",
                   layout,
                   size=(500, 450))

while True:
    event, values = window.read()
    # Die beiden folgenden Zeilen auskommentieren (# entfernen)
    # um events und values zu sehen:
    # print("event:", event)
    # print("values:", values)
    
    if event == sg.WIN_CLOSED or event == "-BEENDEN-":
        break

    if event == "-UEBERTRAGEN-":
        # So kommt ihr an die Werte heran:
        text_eingabe = values["-EINGABE-"]
        # So kommt ihr an die Elemente heran:
        window["-AUSGABE-"].update(text_eingabe)
        
    if event == "-TEST-":
        window["-AUSGABE-"].update("Testknopf gedrückt!")
        
    if event == "-AUSWAHL-":
        nachricht = values["-AUSWAHL-"] + " ausgewählt!"
        window["-AUSGABE-"].update(nachricht)
        
    if event == "-REGLER-":
        nachricht = "Regler: " + str(values["-REGLER-"])
        window["-AUSGABE-"].update(nachricht)

window.close()

2.5 Farbwähler

bildanzeige

import PySimpleGUI as sg

sg.set_options(font=("Courier", 30))

layout = [[sg.Slider(range=(0, 255), default_value=255, orientation="h", key="-RED-")],
          [sg.Slider(range=(0, 255), default_value=0, orientation="h", key="-GREEN-")],
          [sg.Slider(range=(0, 255), default_value=0, orientation="h", key="-BLUE-")],
          [sg.Button("Beenden", key="-QUIT-")]
]

window = sg.Window("Farbmixer", layout)

def rgb_to_hex(r, g, b):
    return "#{:02x}{:02x}{:02x}".format(r, g, b)

while(True):
    event, values = window.read(timeout=100)
    
    if event == sg.WIN_CLOSED or event == "-QUIT-":
        break
    
    red = int(values["-RED-"])
    green = int(values["-GREEN-"])
    blue = int(values["-BLUE-"])
    
    color = rgb_to_hex(red, green, blue)
    
    window["-QUIT-"].update(button_color=('white', color))
    
window.close()

2.6 Farbwähler, kommentiert

import PySimpleGUI as sg

sg.set_options(font=("Courier", 30))

layout = [[sg.Slider(range=(0, 255), orientation="h", key="-RED-")],
          [sg.Slider(range=(0, 255), orientation="h", key="-GREEN-")],
          [sg.Slider(range=(0, 255), orientation="h", key="-BLUE-")],
          [sg.Button("Beenden", key="-QUIT-")]
]

window = sg.Window("Farbmixer", layout)

# Diese Funktion wandelt drei Werte für rot, grün und blau
# in den ensprechenden Hex String um:
def rgb_to_hex(r, g, b):
    return "#{:02x}{:02x}{:02x}".format(r, g, b)

while(True):
    # timeout=100 sorgt dafür, dass die values 10 mal
    # pro Sekunde ausgelesen werden, anstatt auf eine
    # Eingabe zu warten:
    event, values = window.read(timeout=100)
    
    if event == sg.WIN_CLOSED or event == "-QUIT-":
        break
    
    # Die Werte der Slider sind float, also Dezimalzahlen.
    # Sie müssen noch in ganze Zahlen (int) umgewandelt werden.
    # Das erledigt die Funktion int():
    red = int(values["-RED-"])
    green = int(values["-GREEN-"])
    blue = int(values["-BLUE-"])
    
    # Wir nutzen die oben definierte Funktion, um den hex-Wert zu erhalten:
    color = rgb_to_hex(red, green, blue)
    
    # Wir schnappen uns den Quit-Button per window["-QUIT-"]
    # und ändern die Farbe mit .update(button_color=(...)):
    window["-QUIT-"].update(button_color=('white', color))
    
window.close()

3. Projekt Bildbearbeitung

3.1 Bild laden und anzeigen

Download

import PySimpleGUI as sg
import cv2

layout = [
    [sg.Image(key="-IMAGE-")],
    [sg.Button("Bild laden"), sg.Button("Beenden")]
]

window = sg.Window("Bild laden und anzeigen", layout)

while True:
    event, values = window.read()

    if event == sg.WINDOW_CLOSED or event == "Beenden":
        break

    if event == "Bild laden":
        filename = sg.popup_get_file("Bild laden", no_window=True)
        if filename:
            image = cv2.imread(filename)
            image_bytes = cv2.imencode('.png', image)[1].tobytes()
            window["-IMAGE-"].update(data=image_bytes)

window.close()

3.2 Bild laden und anzeigen, kommentiert

import PySimpleGUI as sg
import cv2

layout = [
    [sg.Image(key="-IMAGE-")],
    [sg.Button("Bild laden"), sg.Button("Beenden")]
]

window = sg.Window("Bild laden und anzeigen", layout)

while True:
    event, values = window.read()

    if event == sg.WINDOW_CLOSED or event == "Beenden":
        break
    
    if event == "Bild laden":
        # popup_get_file öffnet ein Filedialog-Fenster zur Auswahl
        # einer Bilddatei.
        # Der Rückgabewert ist der Pfad zur Datei!
        filename = sg.popup_get_file("Bild laden", no_window=True)
        # Wenn es geklappt hat (also filename nicht None ist) ...
        if filename:
            # wird das Bild geladen...
            image = cv2.imread(filename)
            # und zur Darstellung konvertiert...
            image_bytes = cv2.imencode('.png', image)[1].tobytes()
            # und im GUI-Element -Image- angezeigt
            window["-IMAGE-"].update(data=image_bytes)

window.close()

3.4 Kachel ausschneiden und Farbkanäle einzeln anzeigen

import PySimpleGUI as sg
import cv2
import numpy as np

sg.set_options(font=("Courier", 30))

layout = [
    [sg.Image(key="-IMAGE-")],
    [sg.Button("Bild laden"), sg.Button("Beenden")]
]

window = sg.Window("Bild laden und anzeigen", layout)

# NEU: Wir verlagern das umwandeln und anzeigen des Bildes
# in eine Funktion:
def show_image(image):
    image_bytes = cv2.imencode('.png', image)[1].tobytes()
    window["-IMAGE-"].update(data=image_bytes)

while True:
    event, values = window.read()

    if event == sg.WINDOW_CLOSED or event == "Beenden":
        break
    
    if event == "Bild laden":
        filename = sg.popup_get_file("Bild laden", no_window=True)
        if filename:
            image = cv2.imread(filename)
            kachel = image[200:400, 200:400]
            kachel_b = kachel[:,:,0]
            kachel_g = kachel[:,:,1]
            kachel_r = kachel[:,:,2]
            
            image = np.zeros((200, 600, 3))
            image[:,0:200,0] = kachel_b
            image[:,200:400,1] = kachel_g
            image[:,400:600,2] = kachel_r
            show_image(image)
            
window.close()