[英]Random Screens from ScreenManager python kivy
I have in my app some images, each image belongs to a screen and when I press a button I try to get another screen but a random one.我的应用程序中有一些图像,每个图像都属于一个屏幕,当我按下一个按钮时,我尝试获取另一个屏幕,但随机屏幕。 I think I am pretty close to do what I want to do but for 2 days I am stuck at this stage.. when i run my code in the console i have this error " AttributeError: 'ScreenManager' object has no attribute 'random_screen' "
我想我已经很接近做我想做的事了,但是在这个阶段我被困了 2 天。当我在控制台中运行我的代码时,我遇到了这个错误“AttributeError:'ScreenManager' object 没有属性'random_screen' "
And I really don't know where to put that attribute... please heeeelppp: :((而且我真的不知道把那个属性放在哪里......请heeeelppp::((
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()
You got a lot of bugs in there...你那里有很多错误...
Myscreen class isn't connected to your other classes or kv file at all, so that function will not be found at all. Myscreen class 根本没有连接到您的其他类或 kv 文件,因此根本找不到 function。
Your 3rd add.widget call adds the 'Q2' screen instead of Q3您的第三个 add.widget 调用添加了“Q2”屏幕而不是 Q3
Screen does not have a self.source parameter. Screen 没有 self.source 参数。 You need to use the screenmanager to change screens.
您需要使用屏幕管理器来更改屏幕。 root.manager.current = 'Q#' would be the correct way.
root.manager.current = 'Q#' 将是正确的方法。
This worked for me...这对我有用...
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 file .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()
You could also put the method in the app class and in the kv file call it by using您还可以将该方法放入应用程序 class 并在 kv 文件中使用
app.random_screen()
Just means you don't have to repeat the same method in each screen class.只是意味着您不必在每个屏幕 class 中重复相同的方法。
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()
Another thing to consider, and I am not sure how this would work as I haven't used images like the way you are doing, but you could have the button change the image rather then change the screen... In the app class you could have a string property that is changed in the same way the button changes your screen.另一件要考虑的事情,我不确定这将如何工作,因为我没有像您那样使用图像,但是您可以让按钮更改图像而不是更改屏幕......在应用程序 class 中可以有一个字符串属性,该属性的更改方式与按钮更改屏幕的方式相同。 In the kv file, have the image source reference this string property, app.Pic for example below...
在 kv 文件中,让图像源引用此字符串属性 app.Pic,例如下面...
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()
I know this isnt another answer to your original question but as per the above comment here is a really paired back quiz app, to give you an idea of how you can change the question and the answers and use the same buttons and screen...我知道这不是您原始问题的另一个答案,但根据上面的评论,这里是一个真正配对的后备测验应用程序,让您了解如何更改问题和答案并使用相同的按钮和屏幕......
I put everything into the app class, it makes it easier to access from the kv file.我将所有内容都放入应用程序 class 中,这样可以更轻松地从 kv 文件访问。 I tried to add in a few comments to try and expalin the code
我尝试添加一些评论来尝试解释代码
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()
And the KV file和 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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.