Problem mit while-Schleife

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Eckes
User
Beiträge: 18
Registriert: Mittwoch 17. Februar 2021, 17:27

Hallo Leute,

Ich möchte mir einen screen mit animierten Buchstaben basteln.
Es sollen einfach Buchstaben (Grafiken) im Bild hoch und runter laufen.
Folgendes Programm funktioniert aber nicht und ich finde den Grund nicht.

Wenn ich das über Pfeiltasten (mit bind) programmiere, läuft es, aber in einer Schleife hab ich nur noch einen weißen, eingefrorenen Bildschirm.


import time
from tkinter import *
from PIL import ImageTk, Image



main = Tk()
main.title("Test")
main.iconbitmap("prgpix/WindowIcon.ico")
main.geometry("1920x1200+0+0")
# main.wm_minsize(width=640, height=400) # wenn resizable = false, braucht man das hier ja nicht wirklich
main.resizable(width = False, height = False)
#main.configure(bg = "black")
hauptcanvas = Canvas(main, width = 1920, height = 1200, bd = 0, bg = "black", highlightthickness = 0)
hauptcanvas.place(x = 0, y = 0)


def startgedrueckt():
introscreen = False


introscreen = True


e1_pos = 200
c_pos = 250
k_pos = 300
e2_pos = 250
s_pos = 200

e1_pos_add = 1
c_pos_add = 1
k_pos_add = 1
e2_pos_add = 1
s_pos_add = 1

e_img = PhotoImage(file = "Stammtisch\Intro-E.png")
c_img = PhotoImage(file = "Stammtisch\Intro-C.png")
k_img = PhotoImage(file = "Stammtisch\Intro-K.png")
s_img = PhotoImage(file = "Stammtisch\Intro-S.png")

move_e1 = hauptcanvas.create_image(600, e1_pos, image=e_img, anchor="nw", tag="e1")
move_c = hauptcanvas.create_image(750, c_pos, image=c_img, anchor="nw", tag="c")
move_k = hauptcanvas.create_image(900, k_pos, image=k_img, anchor="nw", tag="k")
move_e2 = hauptcanvas.create_image(1050, e2_pos, image=e_img, anchor="nw", tag="e2")
move_s = hauptcanvas.create_image(1200, s_pos, image=s_img, anchor="nw", tag="s")

startbutton_img = ImageTk.PhotoImage(file="Stammtisch\STARTbutton.png")
startbutton = Button(hauptcanvas, borderwidth=0, bg="black", command=startgedrueckt)
startbutton.config(image=startbutton_img, activebackground="black")
startbutton.place(x=830, y=990)

def ani():
global e1_pos, c_pos, k_pos, e2_pos, s_pos, e1_pos_add, c_pos_add, k_pos_add, e2_pos_add, s_pos_add

e1_pos += e1_pos_add
c_pos += c_pos_add
k_pos += k_pos_add
e2_pos += e2_pos_add
s_pos += s_pos_add


print (e1_pos)


if e1_pos > 700:
e1_pos_add = -1
if c_pos > 700:
c_pos_add = -1
if k_pos > 700:
k_pos_add = -1
if e2_pos > 700:
e2_pos_add = -1
if s_pos > 700:
s_pos_add = -1

if e1_pos < 100:
e1_pos_add = 1
if c_pos < 100:
c_pos_add = 1
if k_pos < 100:
k_pos_add = 1
if e2_pos < 100:
e2_pos_add = 1
if s_pos < 100:
s_pos_add = 1

hauptcanvas.move(move_e1, 0, e1_pos_add)
hauptcanvas.move(move_c, 0, e1_pos_add)
hauptcanvas.move(move_k, 0, e1_pos_add)
hauptcanvas.move(move_e2, 0, e1_pos_add)
hauptcanvas.move(move_s, 0, e1_pos_add)




while introscreen:
ani()
#clock.tick(40)
time.sleep(0.1)
Sirius3
User
Beiträge: 17773
Registriert: Sonntag 21. Oktober 2012, 17:20

So funktionieren GUIs nicht; GUIs sind ereignisgesteuert, lang laufende Schleifen darf es nicht geben. Bei Dir löst man das mit `after`.

Daneben solltest Du keine *-Importe benutzen und kein `global`. Variablen. Variablennamen müssen aussagekräftig sein.
Statt jeweils fünf mal den selben Code für jeden Buchstaben würde man eine Buchstabenklasse definieren.

Code: Alles auswählen

import tkinter as tk
from PIL import ImageTk, Image

class Character:
    def __init__(self, canvas, x_position, y_position, filename):
        self.y_position = y_position
        self.canvas = canvas
        self.image = ImageTk.PhotoImage(file=filename)
        self.canvas_id = canvas.create_image(x_position, e1_pos, image=self.image, anchor="nw")
        self.direction = 1
    
    def move(self):
        self.canvas.move(self.canvas_id, 0, self.direction)
        self.y_position += self.direction
        if self.y_position > 700:
            self.direction = -1
        elif self.y_position < 100:
            self.direction = 1


def animation(root, characters):
    for character in characters:
        character.move()
    root.after(100, animation, root, characters)

def main():
    root = tk.Tk()
    root.title("Test")
    root.iconbitmap("prgpix/WindowIcon.ico")
    root.resizable(width=False, height=False)
    canvas = tk.Canvas(root, width=1920, height=1200, bd=0, bg="black", highlightthickness=0)
    canvas.pack()
    buchstaben = [
        Character(canvas, 600, 200, "Stammtisch/Intro-E.png"),
        Character(canvas, 750, 250, "Stammtisch/Intro-C.png"),
        Character(canvas, 900, 300, "Stammtisch/Intro-K.png"),
        Character(canvas, 1050, 250, "Stammtisch/Intro-E.png"),
        Character(canvas, 1200, 200, "Stammtisch/Intro-S.png"),
    ]

    startbutton_img = ImageTk.PhotoImage(file="Stammtisch/STARTbutton.png")
    startbutton = tk.Button(canvas, borderwidth=0, bg="black")
    startbutton.config(image=startbutton_img, activebackground="black")
    startbutton.place(x=830, y=990)
    animation(root, characters)
    root.mainloop()

if __name__ == "__main__":
    main()
Eckes
User
Beiträge: 18
Registriert: Mittwoch 17. Februar 2021, 17:27

Hab es jetzt auch mal so probiert - das läuft auch (hab das so gemacht, weil ich wollte, daß die Buchstaben unterschiedlich "hüpfen"):


import time
from tkinter import *
from PIL import ImageTk, Image



main = Tk()
main.title("Test")
main.iconbitmap("prgpix/WindowIcon.ico")
main.geometry("1920x1200+0+0")
# main.wm_minsize(width=640, height=400) # wenn resizable = false, braucht man das hier ja nicht wirklich
main.resizable(width = False, height = False)
#main.configure(bg = "black")
hauptcanvas = Canvas(main, width = 1920, height = 1200, bd = 0, bg = "black", highlightthickness = 0)
hauptcanvas.place(x = 0, y = 0)


def startgedrueckt():
introscreen = False


introscreen = True


e1_pos = 200
c_pos = 250
k_pos = 300
e2_pos = 250
s_pos = 200

e1_pos_add = 1.1
c_pos_add = 0.9
k_pos_add = 1.3
e2_pos_add = 0.7
s_pos_add = 1.4

e_img = PhotoImage(file = "Stammtisch\Intro-E.png")
c_img = PhotoImage(file = "Stammtisch\Intro-C.png")
k_img = PhotoImage(file = "Stammtisch\Intro-K.png")
s_img = PhotoImage(file = "Stammtisch\Intro-S.png")

move_e1 = hauptcanvas.create_image(600, e1_pos, image=e_img, anchor="nw")
move_c = hauptcanvas.create_image(750, c_pos, image=c_img, anchor="nw")
move_k = hauptcanvas.create_image(900, k_pos, image=k_img, anchor="nw")
move_e2 = hauptcanvas.create_image(1050, e2_pos, image=e_img, anchor="nw")
move_s = hauptcanvas.create_image(1200, s_pos, image=s_img, anchor="nw")

startbutton_img = ImageTk.PhotoImage(file="Stammtisch\STARTbutton.png")
startbutton = Button(hauptcanvas, borderwidth=0, bg="black", command=startgedrueckt)
startbutton.config(image=startbutton_img, activebackground="black")
startbutton.place(x=830, y=990)

def ani():
global e1_pos, c_pos, k_pos, e2_pos, s_pos, e1_pos_add, c_pos_add, k_pos_add, e2_pos_add, s_pos_add

e1_pos += e1_pos_add
c_pos += c_pos_add
k_pos += k_pos_add
e2_pos += e2_pos_add
s_pos += s_pos_add

print (e1_pos)


if e1_pos > 500:
e1_pos_add = -1.1
if c_pos > 500:
c_pos_add = -0.9
if k_pos > 500:
k_pos_add = -1.3
if e2_pos > 500:
e2_pos_add = -0.7
if s_pos > 500:
s_pos_add = -1.4

if e1_pos < 100:
e1_pos_add = 1.1
if c_pos < 100:
c_pos_add = 0.9
if k_pos < 100:
k_pos_add = 1.3
if e2_pos < 100:
e2_pos_add = 0.7
if s_pos < 100:
s_pos_add = 1.4

hauptcanvas.move(move_e1, 0, e1_pos_add)
hauptcanvas.move(move_c, 0, c_pos_add)
hauptcanvas.move(move_k, 0, k_pos_add)
hauptcanvas.move(move_e2, 0, e2_pos_add)
hauptcanvas.move(move_s, 0, s_pos_add)

main.after(1, ani)
Eckes
User
Beiträge: 18
Registriert: Mittwoch 17. Februar 2021, 17:27

warum keine *-importe benutzen ?
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Weil die verschleiern, woher ein Name kommt. Und gerade bei tkinter sind das mal so eben 200, die plötzlich in deinem Namensraum auftauchen. Inklusive so Dinge wie „END“, was man vielleicht auch mal anders definieren will.
Eckes
User
Beiträge: 18
Registriert: Mittwoch 17. Februar 2021, 17:27

ah ja - das stimmt natürlich.
Hab jetzt die Werte nochmal bisschen verändert und es sieht ganz lustig aus. Ich bin ja nicht der mega-Programmierer, aber Python macht irgendwie spaß.
In meinem Alter (ü50) werd' ich wohl keine großen Sachen mehr schaffen, aber es hält zumindest geistig etwas fit denke.

Vielen Dank !
Sirius3
User
Beiträge: 17773
Registriert: Sonntag 21. Oktober 2012, 17:20

@Eckes: auch wenn die Buchstaben jetzt unterschiedlich schnell hüpfen, schreibt man dafür immer noch eine Klasse, halt mit zusätzlichem Geschwindigkeits-Parameter.
Eckes
User
Beiträge: 18
Registriert: Mittwoch 17. Februar 2021, 17:27

okay - dann will ich mich mal dran versuchen :-)
Eckes
User
Beiträge: 18
Registriert: Mittwoch 17. Februar 2021, 17:27

Jetzt aber zum Problem mit der While-Schleife:

wenn man beispielsweise ein Game schreiben will, was ein Intro, einen Hauptteil und eine Ende hat, man aber keine While-Schleife zum Aufrufen der einzelnen Teile nutzen darf, wie kann man das dann realisieren ?

Mein Plan war ja in etwa so:

def intro():
code

def game():
code

def ende():
code

run = True
i = True
g = False
e = False

while run:
if i:
intro()
if g:
game()
if e:
ende():

aber das geht ja nicht wegen dem while.

wie also kann man das intro laufen lassen und die anderen sachen noch nicht und wie dann das intro beenden und das game starten ?
Sirius3
User
Beiträge: 17773
Registriert: Sonntag 21. Oktober 2012, 17:20

Genau, so geht das nicht. Spiele laufen ja meist nur in einem Fenster ab. Das heißt, für Intro, Game und Ende hast Du jeweils einen eigenen Frame, den Du einfach im Hauptfenster austauschen kannst. Also Du startest mit Intro, beim Drücken eines Knopfes wird der Intro-Frame aus dem Hauptfenster gelöscht und statt dessen der Game-Frame erzeugt und dargestellt.
Am besten schreibst Du für jeden der drei Teile jeweils eine Klasse, die von Frame erbt. Dann kannst Du das von der Hauptfensterklasse aus einfach steuern.

Code: Alles auswählen

import tkinter as tk

class Intro(tk.Frame):
    def __init__(self, parent):
        tk.Frame.__init__(self, parent)
        self.parent = parent
        tk.Label(self, text="Intro").pack()
        tk.Button(self, text="Weiter", command=parent.start_game).pack()

class Game(tk.Frame):
    def __init__(self, parent):
        tk.Frame.__init__(self, parent)
        self.parent = parent
        tk.Label(self, text="Game").pack()
        tk.Button(self, text="Ende", command=parent.end_game).pack()


class MainWindow(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        self.current_frame = Intro(self)
        self.current_frame.pack()
    
    def start_game(self):
        self.current_frame.pack_forget()
        self.current_frame = Game(self)
        self.current_frame.pack()
        
    def end_game(self):
        self.destroy()


def main()
    root = MainWindow()
    root.mainloop()

if __name__ == "__main__":
    main()
Eckes
User
Beiträge: 18
Registriert: Mittwoch 17. Februar 2021, 17:27

Das kann ich aber doch sicher auch auf mehrere Dateien verteilen, damit der Code nicht zu lang wird für jeden Teil ?

also müsste ich dann am Anfang

import Intro
import Game

machen ?
Sirius3
User
Beiträge: 17773
Registriert: Sonntag 21. Oktober 2012, 17:20

Man teilt ein Programm so in Module auf, dass jedes Modul eine fachliche Einheit bildet.
Die Teile eines Programms packst Du in ein Package. Module schreibt man, wie Funktionen und Variablen auch, komplett klein.

Code: Alles auswählen

from das_tolle_spiel.intro import Intro
Antworten