Seite 1 von 2
Methode von Objekt B aus Objekt A aufrufen funktioniert nicht
Verfasst: Montag 20. August 2018, 15:31
von Atalanttore
Hallo
Zur Übung erstelle ich gerade ein Hauptmenü für meinen
Reaktionszeittest.
Den Code habe ich entsprechend erweitert:
Code: Alles auswählen
from tkinter import Tk, Button
from random import choice
import time
from statistics import mean
DESIGNATED_COLOR = "red"
SWITCH_TIME = 1000
class Main_Window:
def __init__(self, app_window):
self.app_window = app_window
app_window.title("Game")
app_window.geometry('640x480')
self.start_button = Button(app_window, text="Start", command=game.start_game) # !!!
self.start_button.pack()
self.close_button = Button(app_window, text="Close", command=app_window.quit)
self.close_button.pack()
class Game:
def __init__(self, game_window):
self.game_window = game_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
def start_game(self):
self.game_window.attributes("-fullscreen", True)
self.canvas = Tk.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(DESIGNATED_COLOR)
def change_bg_color(self, color_locked = False):
if self.stop_test == True:
self.game_window.quit()
if not self.color_locked and self.color == DESIGNATED_COLOR:
self.color_missed += 1
self.color_locked = color_locked
current_color = self.color
while True:
if self.color == current_color:
self.color = choice(self.colors)
else:
break
self.canvas.config(bg=self.color)
self.start_time = time.monotonic() # Ereignis Timer
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 stop_game(self):
self.stop_test = True
if self.reaction_times:
# mean() auf Liste ohne Einträge führt zu einem Fehler
print("Gemittelte Reaktionszeit:", mean(self.reaction_times))
print("Reaktionszeit pro richtiger Farbe:", self.reaction_times)
print("Bei richtiger Farbe zu oft gedrückt:", self.key_too_often_pressed)
print("Bei richtiger Farbe nicht gedrückt:", self.color_missed)
print("Bei falscher Farbe gedrückt:", self.false_positives)
def main():
root = Tk()
root.bind("<Escape>", lambda e: game.stop_game())
main_window = Main_Window(root)
game = Game(root)
root.bind("<space>", lambda e: game.key_pressed()) # Ereignis Tastendruck
root.mainloop()
if __name__ == '__main__':
main()
Leider funktioniert der Aufruf der Methode `start_game()` vom Objekt `game` nicht.
Es erscheint folgende Fehlermeldung:
Woran liegt es, dass es so nicht funktioniert?
Gruß
Atalanttore
Re: Methode von Objekt B aus Objekt A aufrufen funktioniert nicht
Verfasst: Montag 20. August 2018, 20:25
von __deets__
Na wie soll das denn gehen, dass du erst das Fenster erzeugst, und *danach* das Game-Objekt, aber schon im MainWindow eben das game-Objekt benutzen willst?
Es gibt verschiedene Arten das Problem zu loesen, aber angesichts der Tatsache, dass dein MainWindow im Grunde gar nichts macht, und umgekehrt dein Game ein sehr intimes Verhaeltnis dazu hat, die beiden Klassen einfach zu einer zusammen zu fassen, und gut ist.
Re: Methode von Objekt B aus Objekt A aufrufen funktioniert nicht
Verfasst: Montag 20. August 2018, 22:18
von Atalanttore
Das Hauptmenü soll alsbald noch um Schaltflächen und Textfelder erweitert werden. Außerdem sollen noch weitere Fenster (u.a. ein Ergebnisfenster) dazukommen.
Gruß
Atalanttore
Re: Methode von Objekt B aus Objekt A aufrufen funktioniert nicht
Verfasst: Montag 20. August 2018, 22:27
von __deets__
Dann musst du eben dem MainWindow das Game bekannt machen, NACHDEM es erzeugt wurde. Die Game klasse manipuliert es ja schon jetzt. Wenn du ein Attribut self.game anlegst, das per default auf None ist, aber dann im Konstruktor von Game auf self setzt, dann geht’s doch.
Re: Methode von Objekt B aus Objekt A aufrufen funktioniert nicht
Verfasst: Samstag 25. August 2018, 16:13
von Atalanttore
__deets__ hat geschrieben: ↑Montag 20. August 2018, 22:27
Wenn du ein Attribut self.game anlegst, das per default auf None ist, aber dann im Konstruktor von Game auf self setzt, dann geht’s doch.
Auch nach mehreren Tagen erschließt sich mir leider nicht was du mit diesem Satz genau meinst.
Das Programm läuft zwar jetzt etwas weiter, aber bei einem Klick auf "Start" wird lediglich das Hauptmenü auf Vollbild vergrößert und in der Konsole erscheint folgender Fehler:
Code: Alles auswählen
AttributeError: type object 'Tk' has no attribute 'Canvas'
Der Code sieht jetzt so aus:
Code: Alles auswählen
from tkinter import Tk, Button
from random import choice
import time
from statistics import mean
DESIGNATED_COLOR = "red"
SWITCH_TIME = 1000
class Main_Window:
def __init__(self, app_window, game=None):
self.game = game
self.app_window = app_window
app_window.title("Game")
app_window.geometry('640x480')
self.start_button = Button(app_window, text="Start", command=game.start_game) # !!!
self.start_button.pack()
self.close_button = Button(app_window, text="Close", command=app_window.quit)
self.close_button.pack()
class Game:
def __init__(self, game_window):
self.game_window = game_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
def start_game(self):
self.game_window.attributes("-fullscreen", True)
self.canvas = Tk.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(DESIGNATED_COLOR)
def change_bg_color(self, color_locked = False):
if self.stop_test == True:
self.game_window.quit()
if not self.color_locked and self.color == DESIGNATED_COLOR:
self.color_missed += 1
self.color_locked = color_locked
current_color = self.color
while True:
if self.color == current_color:
self.color = choice(self.colors)
else:
break
self.canvas.config(bg=self.color)
self.start_time = time.monotonic() # Ereignis Timer
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 stop_game(self):
self.stop_test = True
if self.reaction_times:
# mean() auf Liste ohne Einträge führt zu einem Fehler
print("Gemittelte Reaktionszeit:", mean(self.reaction_times))
print("Reaktionszeit pro richtiger Farbe:", self.reaction_times)
print("Bei richtiger Farbe zu oft gedrückt:", self.key_too_often_pressed)
print("Bei richtiger Farbe nicht gedrückt:", self.color_missed)
print("Bei falscher Farbe gedrückt:", self.false_positives)
def main():
root = Tk()
root.bind("<Escape>", lambda e: game.stop_game())
game = Game(root)
main_window = Main_Window(root, game)
root.bind("<space>", lambda e: game.key_pressed()) # Ereignis Tastendruck
root.mainloop()
if __name__ == '__main__':
main()
Gruß
Atalanttore
Re: Methode von Objekt B aus Objekt A aufrufen funktioniert nicht
Verfasst: Samstag 25. August 2018, 16:59
von Sirius3
Die Klasse ›Main_Window‹ ist eigentlich nur eine Funktion und der Inhalt kann quasi komplett nach ›main‹ verschoben werden. Die Fehlermeldung sagt eigentlich ganz klar, dass eine Tk-Klasse kein Attribut Canvas hat, denn das ist im Modul tkinter.
Zeile 46: explizit auf True prüfen braucht man nicht. `if self.stop_test:`
Zeile 55: eine while-True-Schleife ist nur sinnvoll, wenn die Abbruchbedingung innerhalb des Blocks geprüft wird, hier:
Code: Alles auswählen
current_color = self.color
while self.color == current_color:
self.color = choice(self.colors)
Re: Methode von Objekt B aus Objekt A aufrufen funktioniert nicht
Verfasst: Samstag 25. August 2018, 19:33
von Atalanttore
Danke fürs Durchgehen meines Codes.
Ich habe den angepassten Code nun um ein Ausgabefenster erweitert:
Code: Alles auswählen
from tkinter import *
from random import choice
import time
from statistics import mean
DESIGNATED_COLOR = "red"
SWITCH_TIME = 1000
class Game:
def __init__(self, game_window):
self.game_window = game_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
def start_game(self):
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.quit()
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.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):
self.stop_test = True
results_window = Toplevel(self)
results_window.title("Ergebnisse")
if self.reaction_times:
# mean() auf Liste ohne Einträge führt zu einem Fehler
label_reaction_times = Label(self, text="Gemittelte Reaktionszeit: {}".format(mean(self.reaction_times)))
label_for_listbox = Label(self, text="Reaktionszeit pro richtiger Farbe:")
listbox_reaction_times = Listbox(self)
for item in self.reaction_times:
listbox_reaction_times.insert(item)
label_reaction_times.grid(row=0, column=0)
label_for_listbox.grid(row=1, column=0)
listbox_reaction_times.grid(row=1, column=1)
label_too_often = Label(self, text="Bei richtiger Farbe zu oft gedrückt: {}".format(self.key_too_often_pressed))
label_color_missed = Label(self, text="Bei richtiger Farbe nicht gedrückt: {}".format(self.color_missed))
label_false_positives = Label(self, text="Bei falscher Farbe gedrückt: {}".format(self.false_positives))
ok_button = Button(self, text="OK", command=results_window.quit)
label_too_often.grid(row=2, column=0)
label_color_missed.grid(row=3, column=0)
label_false_positives.grid(row=4, column=0)
ok_button.grid(row=6, column=0)
# if self.reaction_times:
# # mean() auf Liste ohne Einträge führt zu einem Fehler
# print("Gemittelte Reaktionszeit:", mean(self.reaction_times))
# print("Reaktionszeit pro richtiger Farbe:", self.reaction_times)
# print("Bei richtiger Farbe zu oft gedrückt:", self.key_too_often_pressed)
# print("Bei richtiger Farbe nicht gedrückt:", self.color_missed)
# print("Bei falscher Farbe gedrückt:", self.false_positives)
def main():
root = Tk()
root.bind("<Escape>", lambda e: game.show_results())
game = Game(root)
root.bind("<space>", lambda e: game.key_pressed()) # Ereignis Tastendruck
root.title("Spiel")
root.geometry('640x480')
start_button = Button(root, text="Start", command=game.start_game) # !!!
start_button.pack()
close_button = Button(root, text="Schließen", command=root.quit)
close_button.pack()
root.mainloop()
if __name__ == '__main__':
main()
Leider hakt es wieder irgendwo und die Fehlermeldung `AttributeError: '
Game' object has no attribute 'tk'` verstehe ich nicht wirklich.
Mit `
root = Tk()` und `game =
Game(
root)` müsste `
Game` eigentlich `tk` übergeben bekommen haben. `Tk()` und `tk` sind nicht unbedingt dasselbe, aber im Code wird nirgends einem Objekt der Bezeichner `tk` zugewiesen.
Gruß
Atalanttore
Re: Methode von Objekt B aus Objekt A aufrufen funktioniert nicht
Verfasst: Samstag 25. August 2018, 21:08
von __deets__
Ich bekomme den Fehler auch nicht, dein Skript funktioniert fuer mich.
Re: Methode von Objekt B aus Objekt A aufrufen funktioniert nicht
Verfasst: Samstag 25. August 2018, 21:13
von __blackjack__
@Atalanttore: Da im ganzen Quelltext kein `tk` vorkommt, kann das eigentlich nicht sein, und bei mir passiert das auch nicht. Kannst Du den gesamten Traceback zeigen‽
Re: Methode von Objekt B aus Objekt A aufrufen funktioniert nicht
Verfasst: Samstag 25. August 2018, 21:14
von Sirius3
Da Du nicht angegeben hast, wo der Fehler auftritt, kann man nur raten. In ›show_results‹ benutzt Du die Game-Instanz an Stellen, wo eine Tk-Instanz erwartet wird. Geht natürlich nicht.
Re: Methode von Objekt B aus Objekt A aufrufen funktioniert nicht
Verfasst: Sonntag 26. August 2018, 15:47
von Atalanttore
Der komplette Traceback ist folgender,
wenn (hätte ich vielleicht dazu schreiben sollen
) man das Programm mit der ESC-Taste beendet.
Code: Alles auswählen
Exception in Tkinter callback
Traceback (most recent call last):
File "/usr/lib/python3.6/tkinter/__init__.py", line 1702, in __call__
return self.func(*args)
File "/home/ata/source/test.py", line 103, in <lambda>
root.bind("<Escape>", lambda e: game.show_results())
File "/home/ata/source/test.py", line 66, in show_results
results_window = Toplevel(self)
File "/usr/lib/python3.6/tkinter/__init__.py", line 2339, in __init__
BaseWidget.__init__(self, master, 'toplevel', cnf, {}, extra)
File "/usr/lib/python3.6/tkinter/__init__.py", line 2289, in __init__
BaseWidget._setup(self, master, cnf)
File "/usr/lib/python3.6/tkinter/__init__.py", line 2259, in _setup
self.tk = master.tk
AttributeError: 'Game' object has no attribute 'tk'
@Sirius3: Welche Stellen in folgender Funktion ›show_results‹ meinst du genau?
Code: Alles auswählen
def show_results(self):
self.stop_test = True
results_window = Toplevel(self)
results_window.title("Ergebnisse")
if self.reaction_times:
# mean() auf Liste ohne Einträge führt zu einem Fehler
label_reaction_times = Label(self, text="Gemittelte Reaktionszeit: {}".format(mean(self.reaction_times)))
label_for_listbox = Label(self, text="Reaktionszeit pro richtiger Farbe:")
listbox_reaction_times = Listbox(self)
for item in self.reaction_times:
listbox_reaction_times.insert(item)
label_reaction_times.grid(row=0, column=0)
label_for_listbox.grid(row=1, column=0)
listbox_reaction_times.grid(row=1, column=1)
label_too_often = Label(self, text="Bei richtiger Farbe zu oft gedrückt: {}".format(self.key_too_often_pressed))
label_color_missed = Label(self, text="Bei richtiger Farbe nicht gedrückt: {}".format(self.color_missed))
label_false_positives = Label(self, text="Bei falscher Farbe gedrückt: {}".format(self.false_positives))
ok_button = Button(self, text="OK", command=results_window.quit)
label_too_often.grid(row=2, column=0)
label_color_missed.grid(row=3, column=0)
label_false_positives.grid(row=4, column=0)
ok_button.grid(row=6, column=0)
Gruß
Atalanttore
Re: Methode von Objekt B aus Objekt A aufrufen funktioniert nicht
Verfasst: Sonntag 26. August 2018, 16:32
von __blackjack__
@Atalanttore: Die Zeile steht doch im Traceback: ``results_window = Toplevel(self)``.
Re: Methode von Objekt B aus Objekt A aufrufen funktioniert nicht
Verfasst: Sonntag 26. August 2018, 17:06
von Atalanttore
Ich habe die Zeile geändert und meine Überlegungen als Kommentar hinzugefügt:
Code: Alles auswählen
def main():
root = Tk() # 1. Tk-Instanz 'root' wird instanziert
game = Game(root) # 2. Referenz auf Tk-Instanz 'root' wird übergeben
class Game:
def __init__(self, game_window): # 3. Formaler Parameter 'game_window' enthält Referenz auf Tk-Instanz 'root'
self.game_window = game_window # 4. Objektvariable 'self.game_window' bekommt Referenz auf Tk-Instanz 'root'
def show_results(self):
results_window = Toplevel(self.game_window) # 5. Toplevel bekommt Referenz auf die Tk-Instanz 'root'
Funktioniert so leider wieder nicht:
Code: Alles auswählen
Exception in Tkinter callback
Traceback (most recent call last):
File "/usr/lib/python3.6/tkinter/__init__.py", line 1702, in __call__
return self.func(*args)
File "/home/ata/source/test.py", line 103, in <lambda>
root.bind("<Escape>", lambda e: game.show_results())
File "/home/ata/source/test.py", line 82, in show_results
label_too_often = Label(self, text="Bei richtiger Farbe zu oft gedrückt: {}".format(self.key_too_often_pressed))
File "/usr/lib/python3.6/tkinter/__init__.py", line 2763, in __init__
Widget.__init__(self, master, 'label', cnf, kw)
File "/usr/lib/python3.6/tkinter/__init__.py", line 2289, in __init__
BaseWidget._setup(self, master, cnf)
File "/usr/lib/python3.6/tkinter/__init__.py", line 2259, in _setup
self.tk = master.tk
AttributeError: 'Game' object has no attribute 'tk'
Gruß
Atalanttore
Re: Methode von Objekt B aus Objekt A aufrufen funktioniert nicht
Verfasst: Sonntag 26. August 2018, 17:53
von __deets__
Das passt doch alles vorne und hinten nicht zusammmen. Nirgendwo im gezeigten Code kommt ein Label vor. Aber in der Fehlermeldung. Solange Code und Fehler nicht zusammen passen, kann hier doch keiner was dazu sagen.
Re: Methode von Objekt B aus Objekt A aufrufen funktioniert nicht
Verfasst: Sonntag 26. August 2018, 20:14
von Atalanttore
Ich habe nur die von __blackjack__ beschriebene Codezeile geändert.
Gruß
Atalanttore
Re: Methode von Objekt B aus Objekt A aufrufen funktioniert nicht
Verfasst: Sonntag 26. August 2018, 20:22
von __deets__
Ich finde es etwas viel verlangt, das ich mir hier Code aus mehreren Posts zusammen mit vorgeschlagenen Aenderungen selbst zusammen basteln soll, um dann am Ende hoffentlich mit etwas dazustehen, dass dem entspricht, was du da gemacht hast. Und dabei dann auch noch davon auszugehen, dass weder ich noch du etwas falsch verstanden haben.
Wenn du nicht bereit bist, Code mit dazugehoerigem Fehler zu posten, kann ich dir nicht helfen. Und ob andere das koennen, wage ich zu bezweifeln. Das gehoert schon zu deinen Aufgaben, wenn du dir Hilfe wuenschst.
Re: Methode von Objekt B aus Objekt A aufrufen funktioniert nicht
Verfasst: Sonntag 26. August 2018, 20:44
von Atalanttore
__deets__ hat geschrieben: ↑Sonntag 26. August 2018, 20:22
Und dabei dann auch noch davon auszugehen, dass weder ich noch du etwas falsch verstanden haben.
Ich gehe eigentlich davon aus, dass ich etwas falsch verstanden und programmiert habe.
Der Code sieht momentan so aus:
Code: Alles auswählen
from tkinter import *
from random import choice
import time
from statistics import mean
DESIGNATED_COLOR = "red"
SWITCH_TIME = 1000
class Game:
def __init__(self, game_window): # 3. Formaler Parameter 'game_window' enthält Referenz auf Tk-Instanz 'root'
self.game_window = game_window # 4. Objektvariable 'self.game_window' bekommt Referenz auf Tk-Instanz 'root'
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
def start_game(self):
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.quit()
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.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):
self.stop_test = True
results_window = Toplevel(self.game_window) # 5. Toplevel bekommt Referenz auf die Tk-Instanz 'root'
results_window.title("Ergebnisse")
if self.reaction_times:
# mean() auf Liste ohne Einträge führt zu einem Fehler
label_reaction_times = Label(self, text="Gemittelte Reaktionszeit: {}".format(mean(self.reaction_times)))
label_for_listbox = Label(self, text="Reaktionszeit pro richtiger Farbe:")
listbox_reaction_times = Listbox(self)
for item in self.reaction_times:
listbox_reaction_times.insert(item)
label_reaction_times.grid(row=0, column=0)
label_for_listbox.grid(row=1, column=0)
listbox_reaction_times.grid(row=1, column=1)
label_too_often = Label(self, text="Bei richtiger Farbe zu oft gedrückt: {}".format(self.key_too_often_pressed))
label_color_missed = Label(self, text="Bei richtiger Farbe nicht gedrückt: {}".format(self.color_missed))
label_false_positives = Label(self, text="Bei falscher Farbe gedrückt: {}".format(self.false_positives))
ok_button = Button(self, text="OK", command=results_window.quit)
label_too_often.grid(row=2, column=0)
label_color_missed.grid(row=3, column=0)
label_false_positives.grid(row=4, column=0)
ok_button.grid(row=6, column=0)
def main():
root = Tk() # 1. Tk-Instanz 'root' wird instanziert
root.bind("<Escape>", lambda e: game.show_results())
game = Game(root) # 2. Referenz auf Tk-Instanz 'root' wird übergeben
root.bind("<space>", lambda e: game.key_pressed()) # Ereignis Tastendruck
root.title("Spiel")
root.geometry('640x480')
start_button = Button(root, text="Start", command=game.start_game) # !!!
start_button.pack()
close_button = Button(root, text="Schließen", command=root.quit)
close_button.pack()
root.mainloop()
if __name__ == '__main__':
main()
Drückt man während der Programmausführung auf die ESC-Taste kommen folgende Fehler:
Code: Alles auswählen
Exception in Tkinter callback
Traceback (most recent call last):
File "/usr/lib/python3.6/tkinter/__init__.py", line 1702, in __call__
return self.func(*args)
File "/home/ata/source/test.py", line 95, in <lambda>
root.bind("<Escape>", lambda e: game.show_results())
File "/home/ata/source/test.py", line 82, in show_results
label_too_often = Label(self, text="Bei richtiger Farbe zu oft gedrückt: {}".format(self.key_too_often_pressed))
File "/usr/lib/python3.6/tkinter/__init__.py", line 2763, in __init__
Widget.__init__(self, master, 'label', cnf, kw)
File "/usr/lib/python3.6/tkinter/__init__.py", line 2289, in __init__
BaseWidget._setup(self, master, cnf)
File "/usr/lib/python3.6/tkinter/__init__.py", line 2259, in _setup
self.tk = master.tk
AttributeError: 'Game' object has no attribute 'tk'
Gruß
Atalanttore
Re: Methode von Objekt B aus Objekt A aufrufen funktioniert nicht
Verfasst: Sonntag 26. August 2018, 20:51
von __deets__
Und schon bricht Klarheit aus. Schau dir doch mal genau an, WAS du da als erstes Argument uebergibst. Und was das sein sollte.
Re: Methode von Objekt B aus Objekt A aufrufen funktioniert nicht
Verfasst: Montag 27. August 2018, 06:59
von Sirius3
@Atakanttore: ich zitiere mich gerne selbst: In ›show_results‹ benutzt Du die Game-Instanz an Stellen, wo eine Tk-Instanz erwartet wird. Das wichtige daran ist der Plural bei `Stellen`.
Re: Methode von Objekt B aus Objekt A aufrufen funktioniert nicht
Verfasst: Montag 27. August 2018, 10:46
von wuf
Hi Atalanttore
Habe dein Skript ein wenig manipuliert (nicht optimiert):
Code: Alles auswählen
from tkinter import *
from random import choice
import time
from statistics import mean
DESIGNATED_COLOR = "red"
SWITCH_TIME = 1000
class Game:
def __init__(self, game_window): # 3. Formaler Parameter 'game_window' enthält Referenz auf Tk-Instanz 'root'
self.game_window = game_window # 4. Objektvariable 'self.game_window' bekommt Referenz auf Tk-Instanz 'root'
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
def start_game(self):
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.quit()
return
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.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.stop_test = True
results_window = Toplevel(self.game_window) # 5. Toplevel bekommt Referenz auf die Tk-Instanz 'root'
results_window.title("Ergebnisse")
if self.reaction_times:
# mean() auf Liste ohne Einträge führt zu einem Fehler
label_reaction_times = Label(self, text="Gemittelte Reaktionszeit: {}".format(mean(self.reaction_times)))
#label_for_listbox = Label(self, text="Reaktionszeit pro richtiger Farbe:")
#listbox_reaction_times = Listbox(self)
label_for_listbox = Label(results_window, text="Reaktionszeit pro richtiger Farbe:")
listbox_reaction_times = Listbox(results_window)
for item in self.reaction_times:
listbox_reaction_times.insert(item)
label_reaction_times.grid(row=0, column=0)
label_for_listbox.grid(row=1, column=0)
listbox_reaction_times.grid(row=1, column=1)
#label_too_often = Label(self, text="Bei richtiger Farbe zu oft gedrückt: {}".format(self.key_too_often_pressed))
#label_color_missed = Label(self, text="Bei richtiger Farbe nicht gedrückt: {}".format(self.color_missed))
#label_false_positives = Label(self, text="Bei falscher Farbe gedrückt: {}".format(self.false_positives))
#ok_button = Button(self, text="OK", command=results_window.quit)
label_too_often = Label(results_window, text="Bei richtiger Farbe zu oft gedrückt: {}".format(self.key_too_often_pressed))
label_color_missed = Label(results_window, text="Bei richtiger Farbe nicht gedrückt: {}".format(self.color_missed))
label_false_positives = Label(results_window, text="Bei falscher Farbe gedrückt: {}".format(self.false_positives))
ok_button = Button(results_window, text="OK", command=results_window.quit)
label_too_often.grid(row=2, column=0)
label_color_missed.grid(row=3, column=0)
label_false_positives.grid(row=4, column=0)
ok_button.grid(row=6, column=0)
def main():
root = Tk() # 1. Tk-Instanz 'root' wird instanziert
#root.bind("<Escape>", lambda e: game.show_results())
game = Game(root) # 2. Referenz auf Tk-Instanz 'root' wird übergeben
root.bind("<Escape>", lambda e: game.show_results())
root.bind("<space>", lambda e: game.key_pressed()) # Ereignis Tastendruck
root.title("Spiel")
root.geometry('640x480')
start_button = Button(root, text="Start", command=game.start_game) # !!!
start_button.pack()
close_button = Button(root, text="Schließen", command=root.quit)
close_button.pack()
root.mainloop()
if __name__ == '__main__':
main()
Gruss wuf