Seite 1 von 2

Countdown in einem Label

Verfasst: Donnerstag 17. Dezember 2020, 14:30
von Sam123
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()

Re: Countdown in einem Label

Verfasst: Donnerstag 17. Dezember 2020, 14:55
von __deets__
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.

Re: Countdown in einem Label

Verfasst: Donnerstag 17. Dezember 2020, 14:57
von __blackjack__
@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()`.

Re: Countdown in einem Label

Verfasst: Donnerstag 17. Dezember 2020, 16:48
von Sirius3
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()

Re: Countdown in einem Label

Verfasst: Donnerstag 17. Dezember 2020, 18:14
von Sam123
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()

Re: Countdown in einem Label

Verfasst: Donnerstag 17. Dezember 2020, 18:44
von Sirius3
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()

Re: Countdown in einem Label

Verfasst: Freitag 18. Dezember 2020, 12:13
von Sam123
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()

Re: Countdown in einem Label

Verfasst: Freitag 18. Dezember 2020, 13:17
von Sirius3
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()

Re: Countdown in einem Label

Verfasst: Freitag 18. Dezember 2020, 14:43
von Sam123
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()

Re: Countdown in einem Label

Verfasst: Freitag 18. Dezember 2020, 20:37
von Sirius3
Da fehlt doch nur ein `file=` bei PhotoImage.

Re: Countdown in einem Label

Verfasst: Freitag 18. Dezember 2020, 21:32
von Sam123
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?

Re: Countdown in einem Label

Verfasst: Freitag 18. Dezember 2020, 23:43
von Sirius3
Ja, Du brauchst ein Flag und eine start-Methode, die dieses Flag prüft und setzt.

Re: Countdown in einem Label

Verfasst: Samstag 19. Dezember 2020, 00:38
von __blackjack__
@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.

Re: Countdown in einem Label

Verfasst: Mittwoch 23. Dezember 2020, 22:46
von Sam123
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()




Re: Countdown in einem Label

Verfasst: Mittwoch 23. Dezember 2020, 22:55
von __blackjack__
@Sam123: Der Rückgabewert von `pack()` ist `None`.

Re: Countdown in einem Label

Verfasst: Mittwoch 23. Dezember 2020, 23:27
von Sam123
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)

Re: Countdown in einem Label

Verfasst: Donnerstag 24. Dezember 2020, 00:38
von __blackjack__
@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.

Re: Countdown in einem Label

Verfasst: Sonntag 3. Januar 2021, 20:00
von Sam123
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()

Re: Countdown in einem Label

Verfasst: Montag 4. Januar 2021, 09:33
von Sirius3
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.

Re: Countdown in einem Label

Verfasst: Montag 4. Januar 2021, 20:02
von Sam123
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()