Countdown in einem Label

Fragen zu Tkinter.
Sam123
User
Beiträge: 35
Registriert: Freitag 20. November 2020, 12:25

Hallo zusammen,
ich versuche gerade nach einem Tutorial einen Countdown zu programmieren.
Das Beispiel aus dem Tutorial funktioniert auch. Aber wenn ich eigenen Code schreibe, läuft irgendwas schief.
Weiss jemand, was ich falsch mache?

Code: Alles auswählen

import tkinter

def countdown():
    stand = int(label["text"])
    while (stand > 0):
        stand = stand - 1
        label["text"] = str(stand)
        main.after(1000, countdown)

main = tkinter.Tk()
main.geometry("500x300")
main.resizable(0,0)

label = tkinter.Label(main, text = "10", font = ("Arial", 36))
label.place(x = 200, y = 50, anchor = "nw")

button = tkinter.Button(main, text = "Countdown", command = countdown)
button.place(x = 200, y = 200, anchor = "nw" )

main.mainloop()
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich bin sicher in dem Tutorial kommt keine while-Schleife vor. Denn die darf es in einer GUI (so) nicht geben. Zum wiederholten Aufruf ist das after da.
Benutzeravatar
__blackjack__
User
Beiträge: 14084
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Sam123: Die ``while``-Schleife hat da nix zu suchen. Genau das geht bei GUIs ja nicht.

Das speichern des Zählerstands im Label ist unsauber.

Funktionen (und Methoden) sollten alles was sie ausser Konstanten benötigen als Argument(e) übergeben bekommen. Auf Modulebene sollte es keine Variablen geben.

Verwende kein `place()`.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Sirius3
User
Beiträge: 18289
Registriert: Sonntag 21. Oktober 2012, 17:20

Alles auf oberster Ebene muß auch in eine Funktion, die üblicherweise main heißt (kollidiert dann mit dem Hauptfenster, das bei Dir auch main heißt). Dann kommt man auch erst gar nicht in Verlegenheit, globale Variablen zu benutzen.
Um dynamisch Werte anzupassen und auszugeben, kennt TKinter IntVar-Objekte.

Code: Alles auswählen

import tkinter as tk
from functools import partial

def countdown(root, counter):
    counter.set(counter.get() - 1)
    root.after(1000, countdown, root, counter)

def main():
    root = tk.Tk()
    counter = tk.IntVar(root, 10)
    tk.Label(root, textvariable=counter, font=("Arial", 36)).pack()
    tk.Button(root, text="Countdown", command=partial(countdown, root, counter)).pack()
    root.mainloop()

if __name__ == '__main__':
    main()
Sam123
User
Beiträge: 35
Registriert: Freitag 20. November 2020, 12:25

Vielen Dank für eure Hilfe!
Verwende kein `place()`.
@Blackjack: warum eigentlich?

Nun wollte ich aus dem Code von Sirius3 ein kleines Würfelspiel machen, aber es scheitert schon gleich am Anfang.
Der Würfel mit den vier Augen wird zuerst angezeigt. Wenn ich den Button drücke, sollte eigentlich der Würfel mit drei augen erscheinen, aber stattdessen wird nichts angezeigt. Muss ich label_bild etwa wieder zurückgeben? Es funktioniert trotzdem nicht :-(

Code: Alles auswählen

import tkinter as tk
from functools import partial

def wuerfeln(label_bild):
    bild_wuerfel = tk.PhotoImage(file="wuerfel_drei_augen.gif")
    label_bild["image"] = bild_wuerfel

def main():
    root = tk.Tk()

    label_bild = tk.Label(root)
    bild = tk.PhotoImage(file="wuerfel_vier_augen.gif")
    label_bild["image"] = bild
    label_bild.pack()

    tk.Button(root, text="Wuerfeln", command=partial(wuerfeln, label_bild)).pack()

    root.mainloop()

if __name__ == '__main__':
    main()
Sirius3
User
Beiträge: 18289
Registriert: Sonntag 21. Oktober 2012, 17:20

Das ist ein typisches Problem: die PhotoImage-Instanz muß erhalten bleiben, sonst ist das Bild weg. Python räumt aber am Ende der Funktion auf. Um das zu verhindern, kannst Du z.B. das Bild schon in main laden:

Code: Alles auswählen

import tkinter as tk
from functools import partial

def wuerfeln(label_bild, bild):
    label_bild["image"] = bild

def main():
    root = tk.Tk()

    bild_vier_augen = tk.PhotoImage(file="wuerfel_vier_augen.gif")
    bild_drei_augen = tk.PhotoImage(file="wuerfel_drei_augen.gif")
    label_bild = tk.Label(root)
    label_bild["image"] = bild_vier_augen
    label_bild.pack()

    tk.Button(root, text="Wuerfeln", command=partial(wuerfeln, label_bild, bild_drei_augen)).pack()

    root.mainloop()

if __name__ == '__main__':
    main()
Sam123
User
Beiträge: 35
Registriert: Freitag 20. November 2020, 12:25

Also der erste Teil funktioniert schon mal. Aber jetzt habe ich einen Stop-Button eingebaut, damit er dann mit dem würfeln aufhören soll. Ich übergebe einen String als Stopsignal, und wenn dieser String kommt, dann soll die Funktion wuerfeln() verlassen werden. Aber irgndwie macht er dann doch weiter. Irgendwie verstehe ich das nicht :-(

Code: Alles auswählen

import tkinter as tk
from functools import partial
import random

def wuerfeln(root, label_bild, bildliste, button_string):
    print("Button-String: ", button_string)
    if button_string == "Stop-Button":
        return
    zufallszahl = random.randint(1,6)
    print("zufallszahl: ", zufallszahl)
    label_bild["image"] = bildliste[zufallszahl-1]
    root.after(100, wuerfeln, root, label_bild, bildliste, button_string)


def main():
    root = tk.Tk()

    bild_ein_auge = tk.PhotoImage(file="wuerfel_ein_auge.gif")
    bild_zwei_augen = tk.PhotoImage(file="wuerfel_zwei_augen.gif")
    bild_drei_augen = tk.PhotoImage(file="wuerfel_drei_augen.gif")
    bild_vier_augen = tk.PhotoImage(file="wuerfel_vier_augen.gif")
    bild_fuenf_augen = tk.PhotoImage(file="wuerfel_fuenf_augen.gif")
    bild_sechs_augen = tk.PhotoImage(file="wuerfel_sechs_augen.gif")

    bildliste = [bild_ein_auge, bild_zwei_augen, bild_drei_augen, bild_vier_augen, bild_fuenf_augen, bild_sechs_augen]

    label_bild = tk.Label(root)
    label_bild["image"] = bild_vier_augen
    label_bild.pack()

    startbutton_string = "Start-Button"
    stopbutton_string = "Stop-Button"

    tk.Button(root, text="Start", command=partial(wuerfeln, root, label_bild, bildliste, startbutton_string)).pack()
    tk.Button(root, text="Stop", command=partial(wuerfeln, root, label_bild, bildliste, stopbutton_string)).pack()

    root.mainloop()

if __name__ == '__main__':
    main()
Sirius3
User
Beiträge: 18289
Registriert: Sonntag 21. Oktober 2012, 17:20

Du rufst ja mit after immer wieder wuerfeln auf, das ist unabhängig von dem Stop-Aufruf von wuerfeln.

So langsam kommst Du an eine Grenze, wo es mit einfachen Funktionen nicht weiter geht, sondern Du Klassen definieren mußt.
after liefert eine ID zurück, die Du mit after_cancel abbrechen kannst.

Code: Alles auswählen

import tkinter as tk
import random

IMAGES = [
    "wuerfel_ein_auge.gif",
    "wuerfel_zwei_augen.gif",
    "wuerfel_drei_augen.gif",
    "wuerfel_vier_augen.gif",
    "wuerfel_fuenf_augen.gif",
    "wuerfel_sechs_augen.gif",
]

class MainWindow(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        self.cancel_id = None
        self.images = [tk.PhotoImage(image) for image in IMAGES]
        self.label_bild = tk.Label(self, image=self.images[3])
        self.label_bild.pack()
        tk.Button(self, text="Start", command=self.wuerfeln).pack()
        tk.Button(self, text="Stop", command=self.cancel).pack()
       
    def cancel(self):
        if self.cancel_id is not None:
            self.after_cancel(self.cancel_id)
            self.cancel_id = None
    
    def wuerfeln(self):
        self.label_bild["image"] = random.choice(self.images)
        self.cancel_id = self.after(100, self.wuerfeln)


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

if __name__ == '__main__':
    main()
Sam123
User
Beiträge: 35
Registriert: Freitag 20. November 2020, 12:25

Hallo Sirius, danke dir fürs Beispiel. Aber es läuft leider nicht so wie es soll. Es sind nur die beiden Buttons zu sehen. Und die rufen auch die dazugehörigen Funktionen auf, aber es werden keine Bilder angezeigt. Kann es sein, dass es das gleiche Problem ist, wie gestern? :
Das ist ein typisches Problem: die PhotoImage-Instanz muß erhalten bleiben, sonst ist das Bild weg. Python räumt aber am Ende der Funktion auf. Um das zu verhindern, kannst Du z.B. das Bild schon in main laden:
Ich habe deswegen versucht, images in die main() auszulagern und dann zu übergeben, aber dann kommt die Fehlermeldung: Too early to create image. :?

Code: Alles auswählen

import tkinter as tk
import random

IMAGES = ["wuerfel_ein_auge.gif",
          "wuerfel_zwei_augen.gif",
          "wuerfel_drei_augen.gif",
          "wuerfel_vier_augen.gif",
          "wuerfel_fuenf_augen.gif",
          "wuerfel_sechs_augen.gif"
]

class MainWindow(tk.Tk):
    def __init__(self, images):
        tk.Tk.__init__(self)
        self.cancel_id = None
        self.bilder = images
        self.label_bild = tk.Label(self, image=self.bilder[3])
        self.label_bild.pack()
        tk.Button(self, text="Start", command=self.wuerfeln).pack()
        tk.Button(self, text="Stop", command=self.cancel).pack()

    def cancel(self):
            if self.cancel_id is not None:
            self.after_cancel(self.cancel_id)
            self.cancel_id = None

    def wuerfeln(self):
        self.label_bild["image"] = random.choice(self.bilder)
        self.cancel_id = self.after(1000, self.wuerfeln)


def main():

    images = [tk.PhotoImage(image) for image in IMAGES]

    root = MainWindow(images)
    root.mainloop()


if __name__ == '__main__':
    main()
Sirius3
User
Beiträge: 18289
Registriert: Sonntag 21. Oktober 2012, 17:20

Da fehlt doch nur ein `file=` bei PhotoImage.
Sam123
User
Beiträge: 35
Registriert: Freitag 20. November 2020, 12:25

Wenn ich mehrmals auf den Startbutton klicke, werden die Würfel immer schneller?! D.h. wenn ich 10 mal auf den Button drücke, läuft 10 mal die funktion würfeln() gleichzeitig? Kann man das irgendwie unterbinden?
Ich kann eine Variable self.startbutton_aktiv = False in der __init__ definieren und in der funktion wuerfeln() dann auf True setzen. Gibt es eine Möglichkeit, beim drücken vom Startbutton diese Variable abzufragen? Wenn sie aktiv ist, dann die Funktion nicht nochmal ausführen. Oder ist es alles Murks, wie ich mir das vorstelle?
Sirius3
User
Beiträge: 18289
Registriert: Sonntag 21. Oktober 2012, 17:20

Ja, Du brauchst ein Flag und eine start-Methode, die dieses Flag prüft und setzt.
Benutzeravatar
__blackjack__
User
Beiträge: 14084
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Sam123: Man könnte auch den Startbutton deaktivieren, dann bekommt der Nutzer auch gleich noch Rückmeldung das es keinen Sinn macht den zu drücken. Oder man verwendet ein Flag und nur einen Button dessen Text man anpasst, also das da entweder "Start" oder "Stop" steht, je nach dem in welchem Zustand sich das Programm gerade befindet. Abwandlung davon: einen `Checkbutton` verwenden und mit `indicatoron` den als Button darstellen der einrasten kann.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Sam123
User
Beiträge: 35
Registriert: Freitag 20. November 2020, 12:25

Hallo zusammen,
ich habe jetzt den Code etwas abgewandelt, aber es funktioniert wieder nicht. Der Stopbutton wird zwar am Anfang deaktiviert, aber beim drücken des Startbuttons kommt die Fehlermeldung: 'NoneType' object does not support item assignment.
Haben die Buttons keinen Inhalt? <class 'NoneType'> bzw. None. ?

i

Code: Alles auswählen

mport tkinter as tk
import random

IMAGES = [
    "wuerfel_ein_auge.gif",
    "wuerfel_zwei_augen.gif",
    "wuerfel_drei_augen.gif",
    "wuerfel_vier_augen.gif",
    "wuerfel_fuenf_augen.gif",
    "wuerfel_sechs_augen.gif",
]


class MainWindow(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        self.cancel_id = None
        self.images = [tk.PhotoImage(file = image) for image in IMAGES]
        self.label_bild = tk.Label(self, image=random.choice(self.images))
        self.label_bild.pack()
        self.startbutton = tk.Button(self, text="Start", state=tk.NORMAL, command=self.wuerfeln).pack()
        self.stopbutton = tk.Button(self, text="Stop", state=tk.DISABLED, command=self.cancel).pack()

    def cancel(self):
        if self.cancel_id is not None:
            self.after_cancel(self.cancel_id)
            self.cancel_id = None

    def wuerfeln(self):
        print(type(self.startbutton))
        print(self.stopbutton)
        self.startbutton["state"] = tk.DISABLED
        self.stopbutton["state"] = tk.NORMAL
        self.label_bild["image"] = random.choice(self.images)
        self.cancel_id = self.after(100, self.wuerfeln)


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


if __name__ == '__main__':
    main()



Benutzeravatar
__blackjack__
User
Beiträge: 14084
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Sam123: Der Rückgabewert von `pack()` ist `None`.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Sam123
User
Beiträge: 35
Registriert: Freitag 20. November 2020, 12:25

Alles klar, hab die Zeile mit pack() auf zwei Zeilen aufgeteilt. Jetzt läufts, danke!

Code: Alles auswählen

self.startbutton = tk.Button(self, text="Start", state=tk.NORMAL, command=self.wuerfeln)
self.startbutton.pack()
Man kann doch andhand eines Elements seine Position in der Liste ermitteln.
Nun wollte ich in der wuerfeln()-Methode aus dem gewürfelten Bild die gewürfelte Zahl bzw. den Index des Bildes in der Bilderliste ermitteln, aber irgendwie klappt es nicht. Es kommt folgender Fehler:

self.ausgabelabel["text"] = "Ausgabe, gewuerfelte Zahl: {}".format(self.images.index(self.label_bild["image"]))
ValueError: 'pyimage4' is not in list

Code: Alles auswählen

def wuerfeln(self):
        self.startbutton["state"] = tk.DISABLED
        self.stopbutton["state"] = tk.NORMAL
        self.label_bild["image"] = random.choice(self.images)
        self.ausgabelabel["text"] = "Ausgabe gewuerfelte Zahl: {}".format(self.images.index(self.label_bild["image"]))
        self.cancel_id = self.after(100, self.wuerfeln)
Benutzeravatar
__blackjack__
User
Beiträge: 14084
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Sam123: Man kann das Bild nicht mehr aus dem Label holen. Da bekommt man nur den Namen den Tk/Tcl dafür verwendet. Das ist aber auch unsauber so etwas aus der GUI zu ermitteln. Würfelergebnisse sind Zahlen. Also `random.randint()`. Die Zahl willst Du ja eigentlich. Die sollte man sich merken. Und man kann damit auch mit minimalem Aufwand den Index für das Bild ermitteln das angezeigt werden soll.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Sam123
User
Beiträge: 35
Registriert: Freitag 20. November 2020, 12:25

Hallo zusammen,

ich habe jetzt an meinem Würfelspiel etwas weitergemacht und vom Prinzip her funktioniert es auch schon. Aber irgendwie scheinen die Würfel nicht exakt die Kantenlänge zu haben, die ich vorgebe. Weiss jemand woran das liegt?

hier etwas zu lang geratener Code:

Code: Alles auswählen

import tkinter as tk
import random

class MainWindow(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)

        self.kantenlaenge_wuerfel = 100
        self.durchmesser_wuerfelauge = 20
        self.radius_wuerfelauge = self.durchmesser_wuerfelauge/2

        self.cancel_id_wuerfeln = None

        self.rahmen_1 = tk.Frame(self, width=200, height=100, relief="sunken", bd=1)
        self.rahmen_1.pack(padx=10, pady=10)
        self.label_spieler_1 = tk.Label(self.rahmen_1, text="Spieler 1: 0", fg="blue", font="Helvetica 12 bold")
        self.label_spieler_1.pack(ipadx=20, ipady=0, side="left")
        self.label_spieler_2 =tk.Label(self.rahmen_1, text="Spieler 2: 0", fg="red", font="Helvetica 12 bold")
        self.label_spieler_2.pack(ipadx=20, ipady=0, side="left")

        self.rahmen_2 = tk.Frame(self, width=200, height=100, relief="sunken", bd=1)
        self.rahmen_2.pack(padx=10, pady=10)
        self.canvas_1 = tk.Canvas(self.rahmen_2, bg = "blue", height = self.kantenlaenge_wuerfel, width = self.kantenlaenge_wuerfel, bd="1")
        self.canvas_1.pack(padx=10, pady=10, side="left")
        self.canvas_1.create_rectangle(5, 5, self.kantenlaenge_wuerfel-5, self.kantenlaenge_wuerfel-5, fill="white")
        self.canvas_2 = tk.Canvas(self.rahmen_2, bg="red", height=self.kantenlaenge_wuerfel, width=self.kantenlaenge_wuerfel)
        self.canvas_2.create_rectangle(5, 5, self.kantenlaenge_wuerfel - 5, self.kantenlaenge_wuerfel - 5, fill="white")
        self.canvas_2.pack(padx=10, pady=10, side="left")

        self.rahmen_3 = tk.Frame(self, width=200, height=100, relief="sunken", bd=0)
        self.rahmen_3.pack(padx=10, pady=10)
        self.ergebnislabel = tk.Label(self.rahmen_3, text=" ", font="Helvetica 16 bold")
        self.ergebnislabel.pack(ipadx=10, ipady=10, side="top")

        self.rahmen_4 = tk.Frame(self, width=300, height=200, relief="sunken", bd=1)
        self.rahmen_4.pack(padx=10, pady=10)
        self.startbutton = tk.Button(self.rahmen_4, text="Start", state=tk.NORMAL, command=self.wuerfeln)
        self.startbutton.pack(ipadx=10, ipady=10, padx=10, pady=10, side="left")
        self.stopbutton = tk.Button(self.rahmen_4, text="Stop", state=tk.DISABLED, command=self.cancel)
        self.stopbutton.pack(ipadx=10, ipady=10, padx=10, pady=10, side="left")


    def cancel(self):
        self.startbutton["state"] = tk.NORMAL
        self.stopbutton["state"] = tk.DISABLED
        if self.zufallszahl_1 > self.zufallszahl_2:
            self.ergebnislabel["text"] = "Spieler 1 hat gewonnen"
            self.ergebnislabel["fg"] = "blue"
        elif self.zufallszahl_1 < self.zufallszahl_2:
            self.ergebnislabel["text"] = "Spieler 2 hat gewonnen"
            self.ergebnislabel["fg"] = "red"
        else:
            self.ergebnislabel["text"] = "Unentschieden"
            self.ergebnislabel["fg"] = "black"

        if self.cancel_id_wuerfeln is not None:
            self.after_cancel(self.cancel_id_wuerfeln)
            self.cancel_id_wuerfeln = None


    def wuerfeln(self):
        self.ergebnislabel["text"] = ""
        self.startbutton["state"] = tk.DISABLED
        self.stopbutton["state"] = tk.NORMAL
        self.zufallszahl_1 = random.randint(1, 6)
        self.zufallszahl_2 = random.randint(1, 6)
        self.zeichne_wuerfelaugen(self.zufallszahl_1, self.canvas_1)
        self.zeichne_wuerfelaugen(self.zufallszahl_2, self.canvas_2)
        self.label_spieler_1["text"] = "Spieler 1: {}".format(self.zufallszahl_1)
        self.label_spieler_2["text"] = "Spieler 2: {}".format(self.zufallszahl_2)
        self.cancel_id_wuerfeln = self.after(100, self.wuerfeln)


    def zeichne_wuerfelaugen(self, zufallszahl, canvas):
        kantenmitte = self.kantenlaenge_wuerfel / 2
        kantendrittel = self.kantenlaenge_wuerfel / 3

        canvas.create_rectangle(5, 5, self.kantenlaenge_wuerfel - 5, self.kantenlaenge_wuerfel - 5, fill="white")

        if zufallszahl == 1:
            canvas.create_oval(kantenmitte-self.radius_wuerfelauge,kantenmitte-self.radius_wuerfelauge,
                        kantenmitte+self.radius_wuerfelauge,kantenmitte+self.radius_wuerfelauge, fill="black")
        elif zufallszahl == 2:
            canvas.create_oval(kantendrittel - self.radius_wuerfelauge, kantendrittel - self.radius_wuerfelauge,
                        kantendrittel + self.radius_wuerfelauge, kantendrittel + self.radius_wuerfelauge, fill="black")
            canvas.create_oval(2*kantendrittel - self.radius_wuerfelauge, 2*kantendrittel - self.radius_wuerfelauge,
                        2*kantendrittel + self.radius_wuerfelauge, 2*kantendrittel + self.radius_wuerfelauge,fill="black")
        elif zufallszahl == 3:
            canvas.create_oval(2*kantendrittel - self.radius_wuerfelauge, kantendrittel - self.radius_wuerfelauge,
                        2*kantendrittel + self.radius_wuerfelauge, kantendrittel + self.radius_wuerfelauge,fill="black")
            canvas.create_oval(kantenmitte - self.radius_wuerfelauge, kantenmitte - self.radius_wuerfelauge,
                        kantenmitte + self.radius_wuerfelauge, kantenmitte + self.radius_wuerfelauge, fill="black")
            canvas.create_oval(kantendrittel - self.radius_wuerfelauge, 2*kantendrittel - self.radius_wuerfelauge,
                        kantendrittel + self.radius_wuerfelauge, 2*kantendrittel + self.radius_wuerfelauge, fill="black")
        elif zufallszahl == 4:
            canvas.create_oval(kantendrittel - self.radius_wuerfelauge, kantendrittel - self.radius_wuerfelauge,
                        kantendrittel + self.radius_wuerfelauge, kantendrittel + self.radius_wuerfelauge, fill="black")
            canvas.create_oval(2 * kantendrittel - self.radius_wuerfelauge, kantendrittel - self.radius_wuerfelauge,
                        2 * kantendrittel + self.radius_wuerfelauge, kantendrittel + self.radius_wuerfelauge, fill="black")
            canvas.create_oval(kantendrittel - self.radius_wuerfelauge, 2 * kantendrittel - self.radius_wuerfelauge,
                        kantendrittel + self.radius_wuerfelauge, 2 * kantendrittel + self.radius_wuerfelauge, fill="black")
            canvas.create_oval(2*kantendrittel - self.radius_wuerfelauge, 2*kantendrittel - self.radius_wuerfelauge,
                        2*kantendrittel + self.radius_wuerfelauge, 2*kantendrittel + self.radius_wuerfelauge,fill="black")
        elif zufallszahl == 5:
            canvas.create_oval(kantendrittel - self.radius_wuerfelauge, kantendrittel - self.radius_wuerfelauge,
                        kantendrittel + self.radius_wuerfelauge, kantendrittel + self.radius_wuerfelauge, fill="black")
            canvas.create_oval(2 * kantendrittel - self.radius_wuerfelauge, kantendrittel - self.radius_wuerfelauge,
                        2 * kantendrittel + self.radius_wuerfelauge, kantendrittel + self.radius_wuerfelauge, fill="black")
            canvas.create_oval(kantendrittel - self.radius_wuerfelauge, 2 * kantendrittel - self.radius_wuerfelauge,
                        kantendrittel + self.radius_wuerfelauge, 2 * kantendrittel + self.radius_wuerfelauge, fill="black")
            canvas.create_oval(2*kantendrittel - self.radius_wuerfelauge, 2*kantendrittel - self.radius_wuerfelauge,
                        2*kantendrittel + self.radius_wuerfelauge, 2*kantendrittel + self.radius_wuerfelauge,fill="black")
            canvas.create_oval(kantenmitte-self.radius_wuerfelauge,kantenmitte-self.radius_wuerfelauge,
                        kantenmitte+self.radius_wuerfelauge,kantenmitte+self.radius_wuerfelauge, fill="black")
        elif zufallszahl == 6:
            canvas.create_oval(kantendrittel - self.radius_wuerfelauge, kantendrittel - self.radius_wuerfelauge,
                        kantendrittel + self.radius_wuerfelauge, kantendrittel + self.radius_wuerfelauge, fill="black")
            canvas.create_oval(2 * kantendrittel - self.radius_wuerfelauge, kantendrittel - self.radius_wuerfelauge,
                        2 * kantendrittel + self.radius_wuerfelauge, kantendrittel + self.radius_wuerfelauge, fill="black")
            canvas.create_oval(kantendrittel - self.radius_wuerfelauge, 2 * kantendrittel - self.radius_wuerfelauge,
                        kantendrittel + self.radius_wuerfelauge, 2 * kantendrittel + self.radius_wuerfelauge, fill="black")
            canvas.create_oval(2*kantendrittel - self.radius_wuerfelauge, 2*kantendrittel - self.radius_wuerfelauge,
                        2*kantendrittel + self.radius_wuerfelauge, 2*kantendrittel + self.radius_wuerfelauge,fill="black")
            canvas.create_oval(kantendrittel - self.radius_wuerfelauge, kantenmitte - self.radius_wuerfelauge,
                        kantendrittel + self.radius_wuerfelauge, kantenmitte + self.radius_wuerfelauge, fill="black")
            canvas.create_oval(2*kantendrittel - self.radius_wuerfelauge, kantenmitte - self.radius_wuerfelauge,
                        2*kantendrittel + self.radius_wuerfelauge, kantenmitte + self.radius_wuerfelauge, fill="black")


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


if __name__ == '__main__':
    main()
Sirius3
User
Beiträge: 18289
Registriert: Sonntag 21. Oktober 2012, 17:20

Es ist keine gute Idee, ständig neue Punkte zu malen und diese mit immer neunen weißen Rechtecken wieder zu übermalen.
Canvas merken sich alles, was Du jemals "gezeichnet" hast und malen das immer wieder neu.
Der richtige Weg wäre, einmal die sieben Punkte zu erzeugen und jeweils nur die Farbe zu ändern.
Sam123
User
Beiträge: 35
Registriert: Freitag 20. November 2020, 12:25

Hallo Sirius, vielen Dank für deinen Hinweis!
Hab jetzt den Code umgeschrieben. Und es läuft auch. Und das ist auch mein Problem, ich verstehe nicht genau warum.

In der __init__ werden die sieben Augen/Punkte erzeugt. Dabei übergebe ich die Canvas-Flächen auf denen gezeichnet werden soll als Paramter (canvas_1 für Würfel 1 und canvas_2 für Würfel 2). OK, aber wenn ich später die Parameter der Kreise/Punkte verändern will, muss ich diese doch jeweils in einer Variable speichern? (auge_oben_links, auge_oben_rechts...). Und diese Variablen heissen bei mir für beide Würfel/canvas GLEICH. Irgendwie kann es doch nicht richtig sein, oder?

Hier der komplette Code:

Code: Alles auswählen

import tkinter as tk
import random

class MainWindow(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)

        self.kantenlaenge_wuerfel = 150
        self.durchmesser_wuerfelauge = 20
        self.radius_wuerfelauge = self.durchmesser_wuerfelauge/2

        self.cancel_id_wuerfeln = None

        self.rahmen_1 = tk.Frame(self, width=200, height=100, relief="sunken", bd=1)
        self.rahmen_1.pack(padx=10, pady=10)
        self.label_spieler_1 = tk.Label(self.rahmen_1, text="Spieler 1: 0", fg="blue", font="Helvetica 12 bold")
        self.label_spieler_1.pack(ipadx=20, ipady=0, side="left")
        self.label_spieler_2 =tk.Label(self.rahmen_1, text="Spieler 2: 0", fg="red", font="Helvetica 12 bold")
        self.label_spieler_2.pack(ipadx=20, ipady=0, side="left")

        self.rahmen_2 = tk.Frame(self, width=200, height=100, relief="sunken", bd=1)
        self.rahmen_2.pack(padx=10, pady=10)
        self.canvas_1 = tk.Canvas(self.rahmen_2, bg = "blue", height = self.kantenlaenge_wuerfel, width = self.kantenlaenge_wuerfel, bd="1")
        self.canvas_1.pack(padx=10, pady=10, side="left")
        self.canvas_1.create_rectangle(5, 5, self.kantenlaenge_wuerfel-5, self.kantenlaenge_wuerfel-5, fill="white")
        self.canvas_2 = tk.Canvas(self.rahmen_2, bg="red", height=self.kantenlaenge_wuerfel, width=self.kantenlaenge_wuerfel)
        self.canvas_2.create_rectangle(5, 5, self.kantenlaenge_wuerfel - 5, self.kantenlaenge_wuerfel - 5, fill="white")
        self.canvas_2.pack(padx=10, pady=10, side="left")

        self.rahmen_3 = tk.Frame(self, width=200, height=100, relief="sunken", bd=0)
        self.rahmen_3.pack(padx=10, pady=10)
        self.ergebnislabel = tk.Label(self.rahmen_3, text=" ", font="Helvetica 16 bold")
        self.ergebnislabel.pack(ipadx=10, ipady=10, side="top")

        self.rahmen_4 = tk.Frame(self, width=300, height=200, relief="sunken", bd=1)
        self.rahmen_4.pack(padx=10, pady=10)
        self.startbutton = tk.Button(self.rahmen_4, text="Start", state=tk.NORMAL, command=self.wuerfeln)
        self.startbutton.pack(ipadx=10, ipady=10, padx=10, pady=10, side="left")
        self.stopbutton = tk.Button(self.rahmen_4, text="Stop", state=tk.DISABLED, command=self.cancel)
        self.stopbutton.pack(ipadx=10, ipady=10, padx=10, pady=10, side="left")

        self.vorzeichnen_alle_wuerfelaugen(self.canvas_1)
        self.vorzeichnen_alle_wuerfelaugen(self.canvas_2)


    def cancel(self):
        self.startbutton["state"] = tk.NORMAL
        self.stopbutton["state"] = tk.DISABLED
        if self.zufallszahl_1 > self.zufallszahl_2:
            self.ergebnislabel["text"] = "Spieler 1 hat gewonnen"
            self.ergebnislabel["fg"] = "blue"
        elif self.zufallszahl_1 < self.zufallszahl_2:
            self.ergebnislabel["text"] = "Spieler 2 hat gewonnen"
            self.ergebnislabel["fg"] = "red"
        else:
            self.ergebnislabel["text"] = "Unentschieden"
            self.ergebnislabel["fg"] = "black"

        if self.cancel_id_wuerfeln is not None:
            self.after_cancel(self.cancel_id_wuerfeln)
            self.cancel_id_wuerfeln = None


    def wuerfeln(self):
        self.fuelle_alle_wuerfelaugen_weiss(self.canvas_1)
        self.fuelle_alle_wuerfelaugen_weiss(self.canvas_2)
        self.ergebnislabel["text"] = ""
        self.startbutton["state"] = tk.DISABLED
        self.stopbutton["state"] = tk.NORMAL
        self.zufallszahl_1 = random.randint(1, 6)
        self.zufallszahl_2 = random.randint(1, 6)
        self.label_spieler_1["text"] = "Spieler 1: {}".format(self.zufallszahl_1)
        self.label_spieler_2["text"] = "Spieler 2: {}".format(self.zufallszahl_2)
        self.zeichne_wuerfel(self.zufallszahl_1, self.canvas_1)
        self.zeichne_wuerfel(self.zufallszahl_2, self.canvas_2)
        self.cancel_id_wuerfeln = self.after(100, self.wuerfeln)


    def vorzeichnen_alle_wuerfelaugen(self, canvas):
        kantenmitte = self.kantenlaenge_wuerfel / 2
        kantendrittel = self.kantenlaenge_wuerfel / 3

        self.auge_oben_links = canvas.create_oval(kantendrittel - self.radius_wuerfelauge, kantendrittel - self.radius_wuerfelauge,
                    kantendrittel + self.radius_wuerfelauge, kantendrittel + self.radius_wuerfelauge, fill="white")

        self.auge_oben_rechts = canvas.create_oval(2*kantendrittel - self.radius_wuerfelauge, kantendrittel - self.radius_wuerfelauge,
                    2*kantendrittel + self.radius_wuerfelauge, kantendrittel + self.radius_wuerfelauge, fill="white")

        self.auge_unten_links = canvas.create_oval(kantendrittel - self.radius_wuerfelauge, 2 * kantendrittel - self.radius_wuerfelauge,
                    kantendrittel + self.radius_wuerfelauge, 2 * kantendrittel + self.radius_wuerfelauge,fill="white")

        self.auge_unten_rechts = canvas.create_oval(2*kantendrittel - self.radius_wuerfelauge, 2 * kantendrittel - self.radius_wuerfelauge,
                    2*kantendrittel + self.radius_wuerfelauge, 2 * kantendrittel + self.radius_wuerfelauge,fill="white")

        self.auge_mitte = canvas.create_oval(kantenmitte-self.radius_wuerfelauge,kantenmitte-self.radius_wuerfelauge,
                    kantenmitte+self.radius_wuerfelauge,kantenmitte+self.radius_wuerfelauge, fill="white")

        self.auge_mitte_links = canvas.create_oval(kantendrittel - self.radius_wuerfelauge, kantenmitte - self.radius_wuerfelauge,
                    kantendrittel + self.radius_wuerfelauge, kantenmitte + self.radius_wuerfelauge,fill="white")

        self.auge_mitte_rechts = canvas.create_oval(2*kantendrittel - self.radius_wuerfelauge, kantenmitte - self.radius_wuerfelauge,
                    2*kantendrittel + self.radius_wuerfelauge, kantenmitte + self.radius_wuerfelauge,fill="white")


    def fuelle_alle_wuerfelaugen_weiss(self, canvas):
        canvas.itemconfig(self.auge_mitte, fill = "white")
        canvas.itemconfig(self.auge_oben_links, fill="white")
        canvas.itemconfig(self.auge_oben_rechts, fill="white")
        canvas.itemconfig(self.auge_mitte_links, fill="white")
        canvas.itemconfig(self.auge_mitte_rechts, fill="white")
        canvas.itemconfig(self.auge_unten_links, fill="white")
        canvas.itemconfig(self.auge_unten_rechts, fill="white")


    def zeichne_wuerfel(self, zufallszahl, canvas):
        if zufallszahl == 1:
            canvas.itemconfig(self.auge_mitte, fill = "black")
        if zufallszahl == 2:
            canvas.itemconfig(self.auge_oben_links, fill="black")
            canvas.itemconfig(self.auge_unten_rechts, fill="black")
        if zufallszahl == 3:
            canvas.itemconfig(self.auge_unten_links, fill="black")
            canvas.itemconfig(self.auge_mitte, fill="black")
            canvas.itemconfig(self.auge_oben_rechts, fill="black")
        if zufallszahl == 4:
            canvas.itemconfig(self.auge_oben_links, fill="black")
            canvas.itemconfig(self.auge_oben_rechts, fill="black")
            canvas.itemconfig(self.auge_unten_links, fill="black")
            canvas.itemconfig(self.auge_unten_rechts, fill="black")
        if zufallszahl == 5:
            canvas.itemconfig(self.auge_oben_links, fill="black")
            canvas.itemconfig(self.auge_oben_rechts, fill="black")
            canvas.itemconfig(self.auge_mitte, fill="black")
            canvas.itemconfig(self.auge_unten_links, fill="black")
            canvas.itemconfig(self.auge_unten_rechts, fill="black")
        if zufallszahl == 6:
            canvas.itemconfig(self.auge_oben_links, fill="black")
            canvas.itemconfig(self.auge_oben_rechts, fill="black")
            canvas.itemconfig(self.auge_mitte_links, fill="black")
            canvas.itemconfig(self.auge_mitte_rechts, fill="black")
            canvas.itemconfig(self.auge_unten_links, fill="black")
            canvas.itemconfig(self.auge_unten_rechts, fill="black")


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


if __name__ == '__main__':
    main()
Antworten