From d48361e23dcba320ad6e042b140b774e267a4276 Mon Sep 17 00:00:00 2001 From: Martin Putzlocher Date: Sun, 16 Jan 2022 21:52:19 +0100 Subject: [PATCH] Quiz nach MVC-Design --- quiz/neuesquiz.py | 131 ------------------------- quiz/neuesquiz_app.py | 184 +++++++++++++++++++++++++++++++++++ quiz/neuesquiz_controller.py | 139 ++++++++++++++++++++++++++ quiz/neuesquiz_data.py | 69 +++++++++++++ 4 files changed, 392 insertions(+), 131 deletions(-) delete mode 100644 quiz/neuesquiz.py create mode 100644 quiz/neuesquiz_app.py create mode 100644 quiz/neuesquiz_controller.py create mode 100644 quiz/neuesquiz_data.py diff --git a/quiz/neuesquiz.py b/quiz/neuesquiz.py deleted file mode 100644 index b42c81a..0000000 --- a/quiz/neuesquiz.py +++ /dev/null @@ -1,131 +0,0 @@ -import tkinter as tk -from random import randint - -D = {1: "George Washington", 2: "John Adams", 3: "Thomas Jefferson", - 4: "James Madison", 5: "James Monroe"} - -P = list(D.values()) - - -class Application(tk.Frame): - - def __init__(self, master=None): - super().__init__(master) - self.sel=tk.StringVar() - self.chosen=randint(0,len(D)-1) - self.cntCorr=0 - self.cntWrong=0 - #build GUI - self.pack() - self.create_widgets() - print(self.chosen) - - def create_widgets(self): - #Anzeige - - - # Frage - self.lf_q = tk.LabelFrame(self) - self.lf_q["text"]="Frage" - self.lf_q.grid(columnspan=2,column=0, row=1) - - - self.namelabel=tk.Label(self.lf_q) - self.namelabel["text"] = "Wer war der " + str(list(D.keys())[self.chosen]) + ". US-Präsident?" - self.namelabel.grid(column=0,row=0) - - - # Antwort - - self.lf_a = tk.LabelFrame(self) - self.lf_a["text"]="Antwort" - self.lf_a.grid(columnspan=2,column=0, row=2) - - # Antwort 1 - - self.l_a1 = tk.Radiobutton(self.lf_a, variable=self.sel, command=self.selectParty) - self.l_a1["text"]="Test1" - self.l_a1.grid(column=0,row=0) - - # Antwort 2 - - #self.l_a2 = tk.Radiobutton(self.lf_a, variable=self.sel, command=self.selectParty) - #self.l_a2["text"]="Test2" - #self.l_a2.grid(column=0,row=1) - - # Antwort 3 - - self.l_a3 = tk.Radiobutton(self.lf_a, variable=self.sel, command=self.selectParty) - self.l_a3["text"]="Test3" - self.l_a3.grid(column=0,row=2) - - - self.radios=list() - for party in P: - r = tk.Radiobutton(self.lf, text=party, variable=self.sel, value = party, command=self.selectParty) - r.pack(anchor="w") - self.radios.append(r) - - #Button: Check - self.btcheck = tk.Button(self) - self.btcheck["text"] = "Überprüfen" - self.btcheck["command"] = self.checkinput - self.btcheck.grid(column=0,row=2) - - #Button: Go-on - self.btgoon = tk.Button(self) - self.btgoon["text"]="weiter" - self.btgoon["command"]= self.nextq - self.btgoon["state"]="disabled" - self.btgoon.grid(column=1,row=2) - - #Label: Ergebnis - self.reslabel=tk.Label(self) - self.reslabel["text"] = "" - self.reslabel.grid(column=0,row=3) - - #Label: Punkte - self.pointslabel=tk.Label(self) - self.pointslabel["text"] = str(self.cntCorr) + " von " + str(self.cntCorr+self.cntWrong) + " richtig." - self.pointslabel.grid(column=1,row=3) - - #Button: Quit - self.quit = tk.Button(self, text="QUIT", fg="red", - command=root.destroy) - self.quit.grid(column=1,row=4) - - def selectParty(self): - selection=self.sel.get() - print("Partei ausgewählt: " + selection) - - def checkinput(self): - self.btcheck["state"]="disabled" - self.btgoon["state"]="normal" - if self.sel.get() == D[list(D.keys())[self.chosen]]: - self.reslabel["text"]="richtig!" - self.reslabel["fg"]="green" - self.cntCorr+=1 - self.pointslabel["text"] = str(self.cntCorr) + " von " + str(self.cntCorr+self.cntWrong) + " richtig." - - else: - self.reslabel["text"]="falsch." - self.reslabel["fg"]="red" - self.cntWrong+=1 - self.pointslabel["text"] = str(self.cntCorr) + " von " + str(self.cntCorr+self.cntWrong) + " richtig." - - def nextq(self): - self.btgoon["state"]="disabled" - self.btcheck["state"]="normal" - for radio in self.radios: - radio.deselect() - self.chosen=randint(0,len(D)-1) - self.namelabel["text"] = "Politiker: " + list(D.keys())[self.chosen] - self.reslabel["text"] = "" - - def win(self): - print("Gewonnen!") - - -root = tk.Tk() -app = Application(master=root) -app.mainloop() diff --git a/quiz/neuesquiz_app.py b/quiz/neuesquiz_app.py new file mode 100644 index 0000000..783e819 --- /dev/null +++ b/quiz/neuesquiz_app.py @@ -0,0 +1,184 @@ +import tkinter as tk +from tkinter import messagebox as tkm +from tkinter import font as tkfont + +DEBUG = True + +# Acces to Controller +from neuesquiz_controller import * + + + + +class Application(tk.Frame): + """ Graphical Application + + """ + def __init__(self, master=None): + super().__init__(master) + self.set_fonts_for_tkinter() + # Activate Controller + self.controller = Controller(self) + + # Control variable for Radiobuttons + self.selected = tk.StringVar() + + #build GUI + self.pack() + self.create_widgets() + + def create_widgets(self): + # Anzeige + + # Frage + self.lf_q = tk.LabelFrame(self, bg="mintcream") + self.lf_q["text"]="Frage" + self.lf_q.grid(columnspan=2,column=0, row=1, sticky="nwse") + + + self.namelabel=tk.Label(self.lf_q, bg="mintcream") + self.namelabel["text"] = "Wer war der {}. US-Präsident?".format(self.controller.get_key_of_chosen()) + self.namelabel.grid(column=0,row=0) + + # Antwort Frame + + self.lf_a = tk.LabelFrame(self, bg="ghostwhite", labelanchor="n", width=300) + self.lf_a["text"]="Antwort" + self.lf_a.grid(columnspan=2,column=0, row=2, sticky="nwse") + + # Radiobuttons + + self.radios=list() + selected_elements = self.controller.current_selection + for count, (el_key, el_value) in enumerate(selected_elements.items()): + r = tk.Radiobutton(self.lf_a, text=el_value, + variable=self.selected, value=el_key, + command=self.controller.select_answer) + r.grid(column=0, row=count, sticky="nw") + self.radios.append(r) + + #Button: Check + self.btcheck = tk.Button(self) + self.btcheck["text"] = "Überprüfen" + self.btcheck["command"] = self.controller.check_user_selection + self.btcheck.grid(column=0,row=3) + + #Button: Go-on + self.btgoon = tk.Button(self) + self.btgoon["text"]="weiter" + self.btgoon["command"]= self.controller.next_question + self.btgoon["state"]="disabled" + self.btgoon.grid(column=1,row=3) + + #Label: Ergebnis + self.reslabel=tk.Label(self) + self.reslabel["text"] = "" + self.reslabel.grid(column=0,row=4) + + #Label: Punkte + self.pointslabel=tk.Label(self) + self.pointslabel["text"] = "0 von 0 richtig." + self.pointslabel.grid(column=1,row=4) + + #Button: Quit + self.quit = tk.Button(self, text="Beenden", fg="red", + command=root.destroy) + self.quit.grid(column=1,row=5) + + def change_state_user_input(self): + self.btgoon["state"]="disabled" + self.btcheck["state"]="normal" + + def change_state_examine(self): + self.btcheck["state"]="disabled" + self.btgoon["state"]="normal" + + def set_response_correct(self): + self.mark_correct_answer() + self.reslabel["text"]="richtig!" + self.reslabel["fg"]="green" + + def set_response_incorrect(self): + self.mark_answer_incorrect + self.mark_correct_answer() + self.reslabel["text"]="falsch" + self.reslabel["fg"]="red" + + # TODO: coloring of correct answer in green + def mark_correct_answer(self): + pass + + # TODO: coloring of selected answer in red if wrong + def mark_answer_incorrect(self): + pass + + # TODO: reset of all coloring of radiobuttons + def mark_reset(self): + pass + + def update_counter(self): + # get numbers from controller + n_correct = self.controller.get_count_correct() + n_all = self.controller.get_count_all() + # set label + self.pointslabel["text"] = str(n_correct) + " von " + str(n_all) + " richtig." + + def update_answers(self): + # delete old Radiobuttons + self.purge_radios() + + # set new question text + self.namelabel["text"] = "Wer war der {}. US-Präsident?".format(self.controller.get_key_of_chosen()) + + # find out new selection + selected_elements = self.controller.current_selection + + # create new Radiobuttons + for count, (el_key, el_value) in enumerate(selected_elements.items()): + r = tk.Radiobutton(self.lf_a, text=el_value, + variable=self.selected, value=el_key, + command=self.controller.select_answer) + r.grid(column=0, row=count, sticky="nw") + self.radios.append(r) + + # reset of selected variable + self.selected.initialize(value="") + + def purge_radios(self): + for r in self.radios: + r.destroy() + + # TODO: reset of all elements + def reset(self): + pass + + def set_fonts_for_tkinter(self): + # Standardschritfart + self.defaultFont = tkfont.nametofont("TkDefaultFont") + self.defaultFont.configure(family="Helvetica", size=12, weight=tkfont.NORMAL) + # Menu-Schriftart + self.defaultMenuFont = tkfont.nametofont("TkMenuFont") + self.defaultMenuFont.configure(family="Helvetica", size=11, weight=tkfont.NORMAL) + # Schriftart für Eingabefelder / Listboxen … + self.defaultTextFont = tkfont.nametofont("TkTextFont") + self.defaultTextFont.configure(family="Helvetica", size=12, weight=tkfont.NORMAL) + # Schrifart für Monospace + self.defaultFixedFont = tkfont.nametofont("TkFixedFont") + self.defaultFixedFont.configure(family="Courier", size=9, weight=tkfont.NORMAL) + # Schriftart für Spaltenüberschriften + self.defaultHeadingFont = tkfont.nametofont("TkHeadingFont") + self.defaultHeadingFont.configure(family="Courier", size=14, weight=tkfont.BOLD) + # Schriftart für Überschriften (Fenster und Dialoge) + self.defaultCaptionFont = tkfont.nametofont("TkCaptionFont") + self.defaultCaptionFont.configure(family="Courier", size=14, weight=tkfont.BOLD) + # Schriftart für Icon-Beschriftungen + self.defaultIconFont = tkfont.nametofont("TkIconFont") + self.defaultIconFont.configure(family="Helvetica", size=8, weight=tkfont.NORMAL) + # Schriftart für Tooltip-Beschriftungen + self.defaultTooltipFont = tkfont.nametofont("TkTooltipFont") + self.defaultTooltipFont.configure(family="Helvetica", size=8, weight=tkfont.NORMAL) + + +root = tk.Tk() +app = Application(master=root) +app.mainloop() diff --git a/quiz/neuesquiz_controller.py b/quiz/neuesquiz_controller.py new file mode 100644 index 0000000..c568956 --- /dev/null +++ b/quiz/neuesquiz_controller.py @@ -0,0 +1,139 @@ +from random import choice +from neuesquiz_data import * + +DEBUG = True + +class Controller(): + """ Controller of Application + + Schnittstelle zwischen Daten und Anzeige + Steuerung des Programms + """ + def __init__(self, app): + self.app = app + self.data = Quizdata(self) + + self.sample_size = 4 + self.current_selection = dict() # {num: "name of president, …} + self.chosen_element = dict() # {num: "name of president"} single element + self.count_all = 0 + self.count_correct = 0 + + self.test() + + self.make_selection() + + def test(self): + print("===TEST===") + self.data.test_get_random_sample() + print("===TEST===") + + def reset_counter(self): + self.count_all = 0 + self.count_correct = 0 + + def raise_counter(self, correct: bool): + self.count_all = self.count_all + 1 + if correct: + self.count_correct = self.count_correct + 1 + else: + pass + return 0 + + def get_count_all(self): + return self.count_all + + def get_count_correct(self): + return self.count_correct + + def make_selection(self): + # Select sample from the data + sample_size = self.sample_size + self.current_selection = self.data.get_random_sample_dict(sample_size) + + # Select element of the sample to be asked for + self.chosen_element = self.data.get_single_from_sample_dict(self.current_selection) + + # +++ DEBUG + if DEBUG: + print("Dict for selection: {}".format(self.current_selection)) + print("Correct element: {}".format(self.chosen_element)) + # --- DEBUG + + def get_key_of_chosen(self): + key = list(self.chosen_element.keys())[0] + return key + + # TODO: What happens if answer is selcted? + def select_answer(self, event=None): + pass + + def check_user_selection(self): + # Set app to examination mode + self.app.change_state_examine() + + # Get selection of user + user_selection = int(self.app.selected.get()) + # Get key of chosen element + correct_answer = int(self.get_key_of_chosen()) + + #+++DEBUG + if DEBUG: + print("correct answer would be: {}".format(correct_answer)) + print("user selected element: {}".format(user_selection)) + #---DEBUG + + if user_selection is correct_answer: + self.raise_counter(correct=True) + # +++ DEBUG + if DEBUG: + print("correct") + # --- DEBUG + self.app.set_response_correct() + self.app.update_counter() + + else: + self.raise_counter(correct=False) + # +++ DEBUG + if DEBUG: + print("incorrect") + # --- DEBUG + self.app.set_response_incorrect() + self.app.update_counter() + + self.start_timer_next() + return 0 + + def start_timer_next(self): + # automatisches Stellen der nächsten Frage + seconds_to_next = 5 + self.timer = self.app.after(seconds_to_next*1000,self.next_question) + #+++DEBUG + if DEBUG: + print("timer of {} seconds to next question started".format(seconds_to_next)) + #---DEBUG + return self.timer + + def stop_timer_next(self): + self.app.after_cancel(self.timer) + #+++DEBUG + if DEBUG: + print("timer stopped") + #---DEBUG + return 0 + + def next_question(self): + self.stop_timer_next() + + self.make_selection() + self.app.update_answers() + self.app.change_state_user_input() + + # TODO: implement win + def win(self): + print("Gewonnen!") + pass + + # TODO: reset of all elements + def reset(self): + pass diff --git a/quiz/neuesquiz_data.py b/quiz/neuesquiz_data.py new file mode 100644 index 0000000..8fb16ac --- /dev/null +++ b/quiz/neuesquiz_data.py @@ -0,0 +1,69 @@ +from random import sample, choice + +DEBUG = True + +class Quizdata(): + """ Data Model + + """ + def __init__(self, controller): + self.con = controller + + # TODO: full list of presidents + self.D = {1: "George Washington", + 2: "John Adams", + 3: "Thomas Jefferson", + 4: "James Madison", + 5: "James Monroe", + 6: "John Quincy Adams", + 7: "Andrew Jackson", + 8: "Martin Van Buren", + 9: "William Henry Harrison", + 10: "John Tyler", + 11: "James K. Polk", + 12: "Zachary Tayler", + 13: "Millard Fillmore", + 14: "Franklin Pierce", + 15: "James Buchanan", + 16: "Abraham Lincoln", + 17: "Andrew Johnson", + 18: "Ulysses S. Grant", + 19: "Rutherford B. Hayes", + 20: "James A. Garfield", + 21: "Chester A. Arthur" + } + + self.list_of_names = list(self.D.values()) + + def get_random_sample_dict(self, number: int = 4): + # get list of selected keys + selection = sample(sorted(self.D), number) + + # construct dictionary of selected elements + selection_D = dict() + for key in selection: + selection_D[key] = self.D[key] + + return selection_D + + def get_single_from_sample_dict(self, selection_D): + # get random single element from dict + chosen = choice(sorted(selection_D)) # int (key) + + # construct dictionary of chosen element + chosen_D = dict() + chosen_D[chosen] = self.D[chosen] + + return chosen_D + + def test_get_random_sample(self): + s = self.get_random_sample_dict() + print("Quizdata.test: {}".format(s)) + + # TODO: implement loading of data from file + def load_from_file(self, filename: str = None): + pass + + # TODO: saving to file + editor of data + def save_to_file(self, filename: str = None): + pass