我的应用程序中有一些图像,每个图像都属于一个屏幕,当我按下按钮时,我会尝试获得另一个屏幕但却是随机的。我想我很快就要做我想做的事了,但两天来我一直处于这个阶段。。当我在控制台中运行代码时,我会出现以下错误"AttributeError:"ScreenManager"对象没有属性"random_screen">
我真的不知道该把这个属性放在哪里。。。请注意!:(
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from random import choice
class MyScreens(Screen):
screens = ["Q1", "Q2", "Q3"] # ........
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.random_screen()
def random_screen(self, *_):
self.source = choice(self.screens)
class Q1(Screen):
pass
class Q2(Screen):
pass
class Q3(Screen):
pass
class TestApp(App):
def build(self):
sm = ScreenManager()
sm.add_widget(Q1(name='Q1'))
sm.add_widget(Q2(name='Q2'))
sm.add_widget(Q2(name='Q3'))
return sm
if __name__ == '__main__':
TestApp().run()
<Q1>:
Image:
source: 'Q1.png'
FloatLayout:
size: root.width, root.height/2
Button:
size_hint: 0.3, 0.25
pos_hint: {"x":0.09, "top":1.16}
background_color: 1, 1, 1, 0.2
on_release: app.root.random_screen()
<Q2>:
Image:
source: 'Q2.png'
FloatLayout:
size: root.width, root.height/2
Button:
size_hint: 0.3, 0.25
pos_hint: {"x":0.09, "top":1.16}
background_color: 1, 1, 1, 0.2
on_press: app.root.random_screen()
<Q3>:
Image:
source: 'Q3.png'
FloatLayout:
size: root.width, root.height/2
Button:
size_hint: 0.3, 0.25
pos_hint: {"x":0.09, "top":1.16}
background_color: 1, 1, 1, 0.2
on_press: app.root.random_screen()
你有很多bug。。。
-
Myscreen类根本没有连接到其他类或kv文件,因此根本找不到该函数。
-
您的第三次add.widget调用添加了"Q2"屏幕,而不是Q3
-
屏幕没有self.source参数。您需要使用屏幕管理器来更改屏幕。root.manager.current="Q#"将是正确的方式。
这对我有效…
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
import random
class Q1(Screen):
def random_screen(self):
screens = ['Q1', 'Q2', 'Q3']
return random.choice(screens)
class Q2(Screen):
def random_screen(self):
screens = ['Q1', 'Q2', 'Q3']
return random.choice(screens)
class Q3(Screen):
def random_screen(self):
screens = ['Q1', 'Q2', 'Q3']
return random.choice(screens)
class TestApp(App):
def build(self):
sm = ScreenManager()
sm.add_widget(Q1(name='Q1'))
sm.add_widget(Q2(name='Q2'))
sm.add_widget(Q3(name='Q3'))
return sm
if __name__ == '__main__':
TestApp().run()
KV文件
<Q1>:
Image:
source: 'Q1.png'
FloatLayout:
size: root.width, root.height/2
Button:
size_hint: 0.3, 0.25
pos_hint: {"x":0.09, "top":1.16}
background_color: 1, 1, 1, 0.2
on_release: root.manager.current = root.random_screen()
<Q2>:
Image:
source: 'Q2.png'
FloatLayout:
size: root.width, root.height/2
Button:
size_hint: 0.3, 0.25
pos_hint: {"x":0.09, "top":1.16}
background_color: 1, 1, 1, 0.2
on_release: root.manager.current = root.random_screen()
<Q3>:
Image:
source: 'Q3.png'
FloatLayout:
size: root.width, root.height/2
Button:
size_hint: 0.3, 0.25
pos_hint: {"x":0.09, "top":1.16}
background_color: 1, 1, 1, 0.2
on_release: root.manager.current = root.random_screen()
您也可以将该方法放在应用程序类中,并在kv文件中使用调用它
app.random_screen()
这意味着您不必在每个屏幕类中重复相同的方法。
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
import random
class Q1(Screen):
Pass
class Q2(Screen):
Pass
class Q3(Screen):
Pass
class TestApp(App):
def random_screen(self):
screens = ['Q1', 'Q2', 'Q3']
return random.choice(screens)
def build(self):
sm = ScreenManager()
sm.add_widget(Q1(name='Q1'))
sm.add_widget(Q2(name='Q2'))
sm.add_widget(Q3(name='Q3'))
return sm
if __name__ == '__main__':
TestApp().run()
kV:
<Q1>:
Image:
source: 'Q1.png'
FloatLayout:
size: root.width, root.height/2
Button:
size_hint: 0.3, 0.25
pos_hint: {"x":0.09, "top":1.16}
background_color: 1, 1, 1, 0.2
on_release: root.manager.current = app.random_screen()
<Q2>:
Image:
source: 'Q2.png'
FloatLayout:
size: root.width, root.height/2
Button:
size_hint: 0.3, 0.25
pos_hint: {"x":0.09, "top":1.16}
background_color: 1, 1, 1, 0.2
on_release: root.manager.current = app.random_screen()
<Q3>:
Image:
source: 'Q3.png'
FloatLayout:
size: root.width, root.height/2
Button:
size_hint: 0.3, 0.25
pos_hint: {"x":0.09, "top":1.16}
background_color: 1, 1, 1, 0.2
on_release: root.manager.current = app.random_screen()
另一件需要考虑的事情是,我不确定这将如何工作,因为我没有像你这样使用图像,但你可以让按钮更改图像,而不是更改屏幕。。。在应用程序类中,您可以有一个字符串属性,该属性的更改方式与按钮更改屏幕的方式相同。在kv文件中,让图像源引用此字符串属性app。下面的图片示例。。。
from kivy.app import App
from kivy.uix.properties import StringProperty
from kivy.uix.screenmanager import ScreenManager, Screen
import random
class Q1(Screen):
Pass
class TestApp(App):
Pic = StringProperty('Q1.png')
def random_pic(self):
Pics = ['Q1.png', 'Q2.png', 'Q3.png']
self.Pic = random.choice(Pics)
def build(self):
sm = ScreenManager()
sm.add_widget(Q1(name='Q1'))
return sm
if __name__ == '__main__':
TestApp().run()
kV:
<Q1>:
Image:
source: app.Pic
FloatLayout:
size: root.width, root.height/2
Button:
size_hint: 0.3, 0.25
pos_hint: {"x":0.09, "top":1.16}
background_color: 1, 1, 1, 0.2
on_release: app.random_pic()
我知道这不是你原来问题的另一个答案,但根据上面的评论,这里有一个真正配对的问答应用程序,让你知道如何更改问题和答案,并使用相同的按钮和屏幕。。。
我把所有的东西都放进了应用程序类中,这使得从kv文件访问更容易。我试着添加一些评论,试图删除代码
from kivy.app import App
from kivy.properties import StringProperty, BooleanProperty,ObjectProperty, NumericProperty
from kivy.uix.screenmanager import ScreenManager, Screen
TestBank = {1 : {"Current Question": "Press 3", "Correct Answer": "3", "Chosen Answer": "", "Multiple Chocies": ["1","2","3","4"]},
2 : {"Current Question": "Press 4", "Correct Answer": "4", "Chosen Answer": "", "Multiple Chocies": ["1","2","3","4"]},
3 : {"Current Question": "Press 1", "Correct Answer": "1", "Chosen Answer": "", "Multiple Chocies": ["1","2","3","4"]},
4 : {"Current Question": "Press 2", "Correct Answer": "2", "Chosen Answer": "", "Multiple Chocies": ["1","2","3","4"]}}
def CreateTest(A_Test = TestBank):
#do something to randomise your test, maybe select a certain number of questions or merge several test banks etc...
return A_Test
class MenuScreen(Screen):
pass
class ResultScreen(Screen):
pass
class TestScreen(Screen):
pass
class QuizApp(App):
TestCurrentQuestion = StringProperty()
'This is updated when next question is selcted'
ChosenAnswerText = StringProperty()
'Every time an answer is selected this property is updated with the selected answer, then the label is automatically updated'
CurrentQuestion = NumericProperty(1)
'The Next and Previous buttons change this property up or down'
TotalQuestions = 4
AnswerButtonA = StringProperty()
AnswerButtonB = StringProperty()
AnswerButtonC = StringProperty()
AnswerButtonD = StringProperty()
'These are the four answer buttons, the Next and Previous buttons update these properties with the answer options, the button texts are then autmatically updated'
Score = NumericProperty()
def StartTest(self):
self.Test = CreateTest() #The test is created
self.UpdateQuestionAndAnswerButtons() #This method updates the text properties that updates all the buttons
def NextQuestion(self):
self.CurrentQuestion +=1 #changes the current question property +1
self.UpdateQuestionAndAnswerButtons() #This method updates the text properties that updates all the buttons
def PreviousQuestion(self):
self.CurrentQuestion -=1 #changes the current question property -1
self.UpdateQuestionAndAnswerButtons() #This method updates the text properties that updates all the buttons
def UpdateChosenAnswer(self, button):
self.Test[self.CurrentQuestion]["Chosen Answer"] = button.text #so that a score can be calculated, the chosen answer is stored in the dictionary TestBank
self.ChosenAnswerText = self.Test[self.CurrentQuestion]["Chosen Answer"] #ChosenAnswerProperty is updated, this then updates the label so the chosen answer appears on screen
def UpdateQuestionAndAnswerButtons(self):
self.TestCurrentQuestion = self.Test[self.CurrentQuestion]["Current Question"]
#TestCurrentQuestion is the property, it is updated to ["Current Question"] for the Test Dic
self.AnswerButtonA, self.AnswerButtonB, self.AnswerButtonC, self.AnswerButtonD = self.Test[self.CurrentQuestion]["Multiple Chocies"]
#["Multiple Chocies"] is a list containing 4 items, so the four properties are updated in one line
self.ChosenAnswerText = self.Test[self.CurrentQuestion]["Chosen Answer"]
#The chosen answer is updated, this is needed here incase the previous button is selcted, the previous selected answer will be updated to avoid confusion for the user
def CalculateScore(self):
score = 0
for Question in self.Test.keys():
if self.Test[Question]["Chosen Answer"]== self.Test[Question]["Correct Answer"]:
score+=1
self.Score = score
def build(self):
sm = ScreenManager()
sm.add_widget(MenuScreen(name='menu'))
sm.add_widget(ResultScreen(name='result'))
sm.add_widget(TestScreen(name='test'))
return sm
QuizApp().run()
和KV文件
<ResultScreen>
BoxLayout:
orientation: "vertical"
padding: "20px"
spacing: "20px"
BoxLayout:
Label:
text: f"Your Score was {app.Score} out of {app.TotalQuestions}n {round(app.Score/app.TotalQuestions*100)}%"
Label:
text: "PASS" if app.Score/app.TotalQuestions*100 >= 70 else "FAIL" #pass mark is 70%
Button:
text: "Good Bye"
on_press: app.get_running_app().stop()
<MenuScreen>
BoxLayout:
orientation: "vertical"
padding: "20px"
spacing: "20px"
Label:
text:"Wecome to the Test App"
Button:
text: "New Test"
on_press: app.StartTest(); root.manager.current = "test"
<TestScreen>
BoxLayout:
orientation: "vertical"
BoxLayout:
padding: "20px"
orientation: "vertical"
Label:
text: app.TestCurrentQuestion
halign: "center"
Label:
text: app.ChosenAnswerText
GridLayout:
padding: "20px"
spacing: "20px"
cols: 2
rows: 2
Button:
text: app.AnswerButtonA
on_press: app.UpdateChosenAnswer(self)
Button:
text: app.AnswerButtonB
on_press: app.UpdateChosenAnswer(self)
Button:
text: app.AnswerButtonC
on_press: app.UpdateChosenAnswer(self)
Button:
text: app.AnswerButtonD
on_press: app.UpdateChosenAnswer(self)
BoxLayout:
size_hint: (1,None)
orientation: "horizontal"
padding: "20px"
spacing: "20px"
Button:
text: "Previous"
size_hint: (0.3,1)
on_press: app.PreviousQuestion()
disabled: True if app.CurrentQuestion == 1 else False
Button:
text: "Submit"
size_hint: (0.4,1)
on_press: app.CalculateScore(); root.manager.current = "result"
Button:
text: "Next"
on_press: app.NextQuestion();
size_hint: (0.3,1)
disabled: True if app.CurrentQuestion == app.TotalQuestions else False