Methode von Objekt B aus Objekt A aufrufen funktioniert nicht

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.
Atalanttore
User
Beiträge: 407
Registriert: Freitag 6. August 2010, 17:03

@__blackjack__: Okay, jetzt funktioniert `after_cancel()` so wie es soll. Danke für die Erklärung.

Die nächste Macke, die ich dem Programm gerne austreiben würde, ist, dass sich das Programm nach einem Klick auf "OK" im Ergebnisfenster (`results_window`) komplett beendet.

Dieser "OK"-Button wird im Programm mit folgendem Code erzeugt:

Code: Alles auswählen

ok_button = Button(results_window, text="OK", padx=10, pady=10, command=results_window.quit)
Nach meinem Verständnis müsste sich beim Aufruf von `results_window.quit` nur das Ergebnisfenster (`results_window`) schließen und nicht das komplette Programm, aber offensichtlich liege ich da etwas falsch. Wie macht man das richtig?

Aktueller Code:

Code: Alles auswählen

from tkinter import Tk, Canvas, Toplevel, Frame, Label, Button, Listbox
from random import choice
import time
from statistics import mean



DESIGNATED_COLOR = "red"
SWITCH_TIME = 1000



class Game:
    def __init__(self, main_window):
        self.main_window = main_window
        self.colors = ["green", "red", "blue", "yellow", "black"]
        self.color = None
        self.reaction_times = []
        self.false_positives = 0
        self.color_missed = 0
        self.key_too_often_pressed = 0
        self.stop_test = False
        self.color_locked = False
        self.id_value_change_bg_color = 0


    def start_game(self):
        self.game_window = Toplevel(self.main_window)
        self.game_window.attributes("-fullscreen", True)
        self.canvas = Canvas(self.game_window,
                             width=self.game_window.winfo_screenwidth(),
                             height=self.game_window.winfo_screenheight(),
                             highlightthickness=0)
        self.canvas.pack()
        self.change_bg_color()


    def change_bg_color(self, color_locked = False):
        if self.stop_test:
            self.game_window.destroy()


        if not self.color_locked and self.color == DESIGNATED_COLOR:
            self.color_missed += 1

        self.color_locked = color_locked
        current_color = self.color

        while self.color == current_color:
            self.color = choice(self.colors)

        self.canvas.config(bg=self.color)
        self.start_time = time.monotonic() # Ereignis Timer
        self.id_value_change_bg_color = self.game_window.after(SWITCH_TIME, self.change_bg_color)


    def key_pressed(self):
        if self.color == DESIGNATED_COLOR:
            if self.color_locked:
                self.key_too_often_pressed += 1
            else:
                reaction_time = time.monotonic() - self.start_time
                self.reaction_times.append(reaction_time)
                self.color_locked = True
        else:
            self.false_positives += 1


    def show_results(self, event=None):
        self.game_window.after_cancel(self.id_value_change_bg_color)
        self.stop_test = True
        results_window = Toplevel(self.main_window)
        results_frame = Frame(results_window)
        results_window.title("Ergebnisse")

        if self.reaction_times:
            # mean() auf Liste ohne Einträge führt zu einem Fehler

            desc_mean_reaction_time = Label(results_frame, text="Gemittelte Reaktionszeit:")
            desc_reaction_times = Label(results_frame, text="Reaktionszeit pro richtiger Farbe:")

            result_mean_reaction_time = Label(results_frame, text=mean(self.reaction_times))
            result_reaction_times = Listbox(results_frame)

            for item in self.reaction_times:
                result_reaction_times.insert('end', item)

            desc_mean_reaction_time.grid(row=0, column=0)
            desc_reaction_times.grid(row=1, column=0)

            result_mean_reaction_time.grid(row=0, column=1)
            result_reaction_times.grid(row=1, column=1)

        desc_too_often = Label(results_frame, text="Bei richtiger Farbe zu oft gedrückt:")
        desc_color_missed = Label(results_frame, text="Bei richtiger Farbe nicht gedrückt:")
        desc_false_positives = Label(results_frame, text="Bei falscher Farbe gedrückt:")

        result_too_often = Label(results_frame, text=self.key_too_often_pressed)
        result_color_missed = Label(results_frame, text=self.color_missed)
        result_false_positives = Label(results_frame, text=self.false_positives)

        desc_too_often.grid(row=2, column=0)
        desc_color_missed.grid(row=3, column=0)
        desc_false_positives.grid(row=4, column=0)

        result_too_often.grid(row=2, column=1)
        result_color_missed.grid(row=3, column=1)
        result_false_positives.grid(row=4, column=1)

        results_frame.grid(row=0, column=0)

        ok_button = Button(results_window, text="OK", padx=10, pady=10, command=results_window.quit)
        ok_button.grid(row=1, column=0)


def main():
    main_window = Tk()

    game = Game(main_window)

    main_window.bind_all("<Escape>", lambda e: game.show_results())
    main_window.bind_all("<space>", lambda e: game.key_pressed()) # Ereignis Tastendruck
    main_window.title("Spiel")
    main_window.geometry('640x480')

    start_button = Button(main_window, text="Start", padx=10, pady=10, command=game.start_game)
    start_button.pack()
    close_button = Button(main_window, text="Schließen", padx=10, pady=10, command=main_window.quit)
    close_button.pack()

    main_window.mainloop()


if __name__ == '__main__':
    main()

Gruß
Atalanttore
Sirius3
User
Beiträge: 17747
Registriert: Sonntag 21. Oktober 2012, 17:20

Wie kommst Du zu Deinem Verständnis, anstatt einfach in die Hilfe zu schauen:
Quit the Tcl interpreter. All widgets will be destroyed.
Du suchst `destroy`.
Atalanttore
User
Beiträge: 407
Registriert: Freitag 6. August 2010, 17:03

@Sirius3: Kurze Zwischenfrage: Welche Hilfe verwendest du für Tkinter?

`results_window.destroy` funktioniert schon besser. Allerdings bleibt das `game_window` weiterhin im Vollbildmodus geöffnet, obwohl es durch `self.game_window.destroy()` in Zeile 40 doch eigentlich beendet werden sollte, wenn `self.stop_test` nach einem Druck auf die ESC-Taste wahr wird.

Gruß
Atalanttore
Antworten