首页 > 解决方案 > 用 Kivy 语言重绘按钮和其他小部件

问题描述

我正在尝试使用 Kivy 语言编写类似于谁想成为百万富翁的游戏。我对小部件的动态功能有疑问。

我想要做的是当用户单击选项按钮以选择答案时,该按钮会保持向下状态一段时间,然后根据正确答案切换颜色。然后同一个屏幕应该更新并给我新的问题,所有颜色都已重置。这是我正在处理的代码的相关部分。忽略我有两个问题生成器的事实,一旦我确定这个问题生成器正常工作,我将切换到随机问题生成器。

class PlayScreen(Screen):
    question = StringProperty()
    question_id = StringProperty()
    option_a = StringProperty()
    option_b = StringProperty()
    option_c = StringProperty()
    option_d = StringProperty()

    def __init__(self, **kwargs):
        super(PlayScreen, self).__init__(**kwargs)
        self.Questions = dict([('id12345', "What is the capital city of Azerbaijan"), ('idd5', "What is the capital city of Turkey")])
        self.Answer_Set = dict([('id12345', ["Ganja", "Baku", "Lankaran", "Ghakh"]), ('idd5', ["Istanbul", "Tiflis", "Ankara", "Izmir"])])
        self.Correct_Answers = dict([('id12345', "Baku"), ('idd5', "Ankara")])
        self.Question_IDs = list(self.Questions.keys())

        self.question_builder()


    def question_builder(self):
        self.question_id  =self.Question_IDs[0]   #randint(0, len(self.Questions))
        self.question = self.Questions[self.question_id]
        self.option_a = self.Answer_Set[self.question_id][0]
        self.option_b = self.Answer_Set[self.question_id][1]
        self.option_c = self.Answer_Set[self.question_id][2]
        self.option_d = self.Answer_Set[self.question_id][3]
        return self.question

    def question_builder_2(self):
        self.question_id  =self.Question_IDs[1]   #randint(0, len(self.Questions))
        self.question = self.Questions[self.question_id]
        self.option_a = self.Answer_Set[self.question_id][0]
        self.option_b = self.Answer_Set[self.question_id][1]
        self.option_c = self.Answer_Set[self.question_id][2]
        self.option_d = self.Answer_Set[self.question_id][3]
        return self.question

    def checker(self, instance, question_id):
        if instance.text == self.Correct_Answers[question_id]:
            return True
        else:
            return False

Kivy_language_body = """
<PlayScreen>:
    name: "play"
    GridLayout:
        question: root.question
        question_id: root.question_id
        option_a: root.option_a
        option_b: root.option_b
        option_c: root.option_c
        option_d: root.option_d
        default_color: root.default_color

        id: PlayScreenGrid
        cols:1
        rows: 2
        GridLayout:
            id: q
            cols: 1
            rows: 1
            size: root.width, root.height/2
            pos_hint: {"center_x":0.5, "top":1}
            canvas.before:
                Color:
                    rgb: 1,0,0
                Rectangle:
                    pos: self.pos
                    size: self.size
            Label:
                text: PlayScreenGrid.question
                font_size: 20

        GridLayout:
            cols: 2
            rows: 2
            size: root.width, root.height/2
            pos_hint: {"y":0}

            Button:
                id: a
                text: root.option_a
                font_size: 20
                min_state_time: 4

                on_release:
                    a.background_color = 1, 1, 1, 1
                    self.trigger_action(duration=5)
                    self.state = "down"
                    print (self.state)
                    self.state = "normal"
                    print(self.state)
                    if root.checker(a, root.question_id): a.background_color = 1,1,0,1
                    else: a.background_color = 100,0,0,0.5
                    self.parent._trigger_layout()
                    root.question_builder_2()


            Button:
                id: b
                text: root.option_b
                font_size: 20
                on_release:
                    self.state = "down"
                    self.state = app.timer()
                    if root.checker(b, root.question_id): b.background_color = 1,1,0,1
                    else: b.background_color = 100,0,0,0.5



            Button:
                id: c
                text: root.option_c
                font_size: 20
                on_release:
                    self.state = "down"
                    app.timer()
                    self.state = "normal"
                    if root.checker(c, root.question_id): c.background_color = 1,1,0,1
                    else: c.background_color = 100,0,0,0.5
                    app.timer()
                    c.background_color = 1,1,1,1
                    app.timer()
                    if root.checker(c, root.question_id): root.question_builder_2()

            Button:
                id: d
                text: root.option_d
                font_size: 20
                on_release:
                    self.state = "down"
                    app.timer()
                    self.state = "normal"
                    if root.checker(d, root.question_id): d.background_color = 1,1,0,1
                    else: d.background_color = 100,0,0,0.5
                    app.timer()
                    d.background_color = 1,1,1,1
                    app.timer()
                    if root.checker(d, root.question_id):
root.question_builder_2()
"""

标签: python-3.xkivykivy-language

解决方案


我上面提到的问题的一个有点丑陋的解决方案

class Countdown(Label):
a = NumericProperty(1)  # seconds for button to remain in down state before the answer is revealed
b = NumericProperty(0.5) # seconds for button to remain in red or green color after answer is revealed before the next action

def __init__(self, instance, background_color, correct):
    super(Countdown, self).__init__()
    self.intance = instance
    self.background_color = background_color
    self.correct = correct

def start(self,):
    Animation.cancel_all(self)  # stop any current animations
    self.anim = Animation(a=0, duration=self.a)
    self.anim.bind(on_complete=self.finish_callback)
    self.anim.start(self)

def start_2(self):
    self.anime = Animation(a=0, duration=self.b)
    self.anime.bind(on_complete=self.open_popup)
    self.anime.start(self)

def finish_callback(self, animation, incr_crude_clock):
    self.instance.background_color = self.background_color  # color based on answer
    self.start_2()

def open_popup(self, animation, incr_crude_clock):
    if self.correct:
        Factory.CorrectPopup().open()   # custom popup appears if answered correctly
    else:
        Factory.WrongPopup().open()     # custom popup appears if answered wrong

def on_a(self, instance, value):
    self.instance.state = "down"
    for button in self.instance.parent.children:    # disable all other buttons to prevent user from clicking them randomly
        if hasattr(button, 'id'):
            if button.id != self.instance.id:
                button.disabled = True
# Basic grid with question and 4 answer choices:
class PlayGrid(FloatLayout):
    def __init__(self, **kwargs):
        self.clear_widgets()
        super(PlayGrid, self).__init__(**kwargs)
        self.question = StringProperty()
        self.id = 'plygrd'

        self.cols = 1
        self.question_grid = GridLayout()
        self.answer_grid = GridLayout()
        self.answer_grid.id = 'ansgrd'
        self.button_grid = FloatLayout()

        self.answer_grid.cols = 2
        self.answer_grid.rows = 2
        self.answer_grid.size_hint = 1, 0.5
        self.answer_grid.pos_hint = {'y': 0}

        self.question_grid.size_hint = 1, 0.5
        self.question_grid.cols = 1
        self.question_grid.rows = 1
        self.question_grid.pos_hint = {'center_y': 0.5}
        self.question_grid.pos_hint = {'center_x': 0.5}
        self.question_grid.pos_hint = {'top': 0.85}
        self.question_builder()
        self.question_grid.question_panel = Label(text=self.question, id=self.question_id, font_size=50,
                                              halign="center", valign='middle')
        self.question_grid.clock = Countdown(None, None, False)
        self.question_grid.add_widget(self.question_grid.question_panel)

        self.add_widget(self.button_grid)
        self.add_widget(self.question_grid)
        self.add_widget(self.answer_grid)

        self.builder()

    def builder(self):
        for i in range(4):
            setattr(self.answer_grid, 'button_'+str(i), Button(text=Answer_Set[self.question_id][i], font_size=40, id='option_'+str(i), background_color=[100, 10, 0, 0.5]))
        getattr(self.answer_grid,'button_'+str(i)).bind(on_press=self.starter)
        self.answer_grid.add_widget(getattr(self.answer_grid,'button_'+str(i)))
    def starter(self, instance):
        if instance.text == Correct_Answers[self.question_id]:
            self.calculate_score(correct=True)
            instance.parent.parent.question_grid.clock.instance = instance
            instance.parent.parent.question_grid.clock.background_color = [0,1,0,1]
            instance.parent.parent.question_grid.clock.correct = True
            instance.parent.parent.question_grid.clock.start()
        else:
            self.calculate_score(correct=False)
            instance.parent.parent.question_grid.clock.instance = instance
            instance.parent.parent.question_grid.clock.background_color = [1,0,0,1]
            instance.parent.parent.question_grid.clock.correct = False
            instance.parent.parent.question_grid.clock.start()

    def question_builder(self):
        while True:
            self.question_id = Question_IDs[randint(0, len(Question_IDs)-1)]
            if self.question_id not in _cache:
                _cache.append(self.question_id)
                break
        self.question = Questions[self.question_id]

推荐阅读