I created an Quiz app in Kivy, when a question is presented there are 4 options (4 toggle buttons). Selecting a toggle button selects an answer and your answer is stored so to calculate the results.
At the end of the quiz, there is an option to review the quiz. The same screen is used as during the test but this time the 4 toggle buttons are disabled. Here is where I am having difficult trying to recreate a feature in KivyMD that I had in Kivy...
During the review, each toggle button is disabled but the text color indicates the right or wrong answer. The correct answer text color is "Green", if the user selected a wrong answer this text color is "Red" and all other buttons are just left as default. If the user selected the correct answer there is just one "Green" text and all others are default.
then I created an attribute UpdateButtons() that when called would check if it was "Test Mode" or "Review Mode". If the test was in "Test Mode", these properties would be set to a default color but if it was in "Review Mode" the color would be set based on the correct answer and on the answer given by the user. The UpdateButtons() was called ever time the user went from one questions to another...
Now, I think my problem lies with KivyMD using themes and there is much more things happening in the background and so my UpdateButtons() is being over written but a kivy toggle button attribute!
I have spent all morning looking through the KivyMD modules and did find some attributes that I tried to modify when I created my MyToggleButton class but the best i could do was to get the text to "Green" or "Red" or whatever during the test mode, in the "Review Mode" the text color kept defaulting back. In default mode the buttons are all set to Disable so I am thinking that there is an
attribute somewhere that sets the button text to a certain color when its disabled. But I couldn't find it!!
Sorry about the long question but just wanted to give sufficient detail... Below is the code and KV file, I tried to peel out all the unnecessary code and just leave in enough to show what I am trying to do!!
from kivymd.uix.screenmanager import MDScreenManager
from kivymd.uix.screen import MDScreen
from kivy.properties import StringProperty, BooleanProperty,ObjectProperty, NumericProperty
from random import shuffle
from kivymd.uix.behaviors.toggle_behavior import MDToggleButton
from kivymd.uix.button import MDRoundFlatButton
source = [
{"question":"Press 1","A":"1","B":"2","C":"3","D":"4","answer":"A"},
{"question":"Press 2","A":"3","B":"2","C":"1","D":"4","answer":"B"},
{"question":"Press 3","A":"2","B":"2","C":"3","D":"4","answer":"C"},
{"question":"Press 4","A":"1","B":"4","C":"2","D":"3","answer":"D"},
]
TestQuestions = {}
for dict in source:
TestQuestions[dict["question"]] = ([dict["A"].title(),dict["B"].title(),dict["C"].title(),dict["D"].title() ],dict[dict["answer"]].title() )
def CreateTest(test = TestQuestions):
Test = {}
for Number, Question in enumerate([x for x in test.keys()]):
Test[Number+1] = {
"Current Question" : Question,
"Correct Answer" : TestQuestions[Question][1],
"Chosen Answer" : "Blank",
"Multiple Chocies" : TestQuestions[Question][0]}
return Test
class QuestionsScreen(MDScreen):
pass
class ResultScreen(MDScreen):
pass
class TestScreen(MDScreen):
pass
class MyToggleButton(MDRoundFlatButton, MDToggleButton):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.background_down = MDApp.get_running_app().theme_cls.primary_dark
class QuizTestApp(MDApp):
Status = BooleanProperty(False)
TestComplete = BooleanProperty(False)
Test = ObjectProperty()
PassMark = 70
TestCurrentQuestion = StringProperty()
CurrentQuestionText = StringProperty("1")
TotalQuestionsText = StringProperty("1")
ChosenAnswerText = StringProperty()
CurrentQuestion = 1
TotalQuestions = NumericProperty(1)
AnswerButtonA = StringProperty()
AnswerButtonB = StringProperty()
AnswerButtonC = StringProperty()
AnswerButtonD = StringProperty()
AnswerButtonA_state = StringProperty("normal")
AnswerButtonB_state = StringProperty("normal")
AnswerButtonC_state = StringProperty("normal")
AnswerButtonD_state = StringProperty("normal")
Score = NumericProperty()
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.Status = False
self.CorrectAnswer = ""
self.TestComplete = False
self.CurrentQuestion = 1
self.Test = CreateTest()
self.TotalQuestions = 4
self.TotalQuestionsText = str(self.TotalQuestions)
self.UpdateQuestionAndAnswerButtons()
def UpdateChosenAnswer(self, button):
self.Test[self.CurrentQuestion]["Chosen Answer"] = button.text
self.ChosenAnswerText = self.Test[self.CurrentQuestion]["Chosen Answer"]
self.DisableSubmitButton()
def NextQuestion(self):
self.CurrentQuestion +=1
self.UpdateQuestionAndAnswerButtons()
def PreviousQuestion(self):
self.CurrentQuestion -=1
self.UpdateQuestionAndAnswerButtons()
def StartTest(self, number):
self.Status = False
self.CorrectAnswer = ""
self.TestComplete = False
self.CurrentQuestion = 1
self.Test = CreateTest(int(number), occuarnces = self.Stats["Questions Breakdown"])
self.TotalQuestions = int(number)
self.TotalQuestionsText = str(self.TotalQuestions)
self.UpdateQuestionAndAnswerButtons()
def UpdateQuestionAndAnswerButtons(self):
self.CurrentQuestionText = str(self.CurrentQuestion)
self.TestCurrentQuestion = self.Test[self.CurrentQuestion]["Current Question"]
self.AnswerButtonA, self.AnswerButtonB, self.AnswerButtonC, self.AnswerButtonD = self.Test[self.CurrentQuestion]["Multiple Chocies"]
self.ChosenAnswerText = self.Test[self.CurrentQuestion]["Chosen Answer"]
self.HighLightButtonIfAnswered()
def HighLightButtonIfAnswered(self):
self.AnswerButtonA_state = "normal"
self.AnswerButtonB_state = "normal"
self.AnswerButtonC_state = "normal"
self.AnswerButtonD_state = "normal"
def func(button_text):
if self.Test[self.CurrentQuestion]["Chosen Answer"] == button_text:
return "down"
elif self.Test[self.CurrentQuestion]["Chosen Answer"] == "Blank":
return "normal"
else:
return "normal"
self.AnswerButtonA_state = func(self.AnswerButtonA)
self.AnswerButtonB_state = func(self.AnswerButtonB)
self.AnswerButtonC_state = func(self.AnswerButtonC)
self.AnswerButtonD_state = func(self.AnswerButtonD)
def SubmitTest(self):
if self.Status == False:
self.Score = self.CalculateScoreAndUpdateTestQuestionsBreakdown()
def DisableSubmitButton(self):
for Question in self.Test.keys():
if self.Test[Question]["Chosen Answer"] == "Blank":
self.TestComplete = False
break
else:
self.TestComplete = True
def CalculateScoreAndUpdateTestQuestionsBreakdown(self):
score = 0
for Question in self.Test.keys():
if self.Test[Question]["Chosen Answer"]== self.Test[Question]["Correct Answer"]:
score+=1
return score
def StartReview(self):
self.TestComplete = True
self.Status = True
self.CurrentQuestion = 1
self.CurrentQuestionText = str(self.CurrentQuestion)
def build(self):
self.theme_cls.theme_style = "Light"
self.theme_cls.primary_palette = "BlueGray"
sm = MDScreenManager()
sm.add_widget(TestScreen(name='test'))
sm.add_widget(ResultScreen(name='result'))
return sm
QuizTestApp().run()