简体   繁体   English

Python、Kivy:从不同类/屏幕调用函数时出现问题

[英]Python, Kivy: Problem with calling functions from different classes/screens

I'm having trouble with correctly calling functions from different classes.我无法正确调用来自不同类的函数。

I am making a simple game which calculates the score using the amount of time it takes to clear a level.我正在制作一个简单的游戏,它使用通关所需的时间来计算分数。 There's a stopwatch running in the background and I want to add a pause button that popup menu, and a resume button inside this popup menu.有一个秒表在后台运行,我想在弹出菜单中添加一个暂停按钮,并在这个弹出菜单中添加一个恢复按钮。

The problem is that when calling the pause function from within the popup menu, it will also be returned inside the popup, instead of inside the main widget.问题是当从弹出菜单中调用暂停 function 时,它也会在弹出菜单中返回,而不是在主窗口小部件中。

Here is a simplified version of the code:这是代码的简化版本:

import kivy
from kivy.app import App
from kivy.lang import Builder
from kivy.properties import NumericProperty
from kivy.uix.widget import Widget
from kivy.uix.popup import Popup
from kivy.clock import Clock

root_widget = Builder.load_file('app.kv')


class ExampleWidget(Widget):
    time = NumericProperty(0)
    paused = False
    stop = False

    # Keeping time
    def increment_time(self, interval):

        self.time += .1
        print(self.time)  # To check if stopwatch is running or not

    # Stop should mean that the stopwatch must reset when it starts again.
    # When paused it should resume when it starts again
    def stop_start_or_pause(self):

        # stop stopwatch
        if self.stop:
            Clock.unschedule(self.increment_time)
            print('Stopped')

        # Make sure time is 0 when restarting
        elif not self.stop and not self.paused:
            # Keeping time
            self.time = 0
            Clock.schedule_interval(self.increment_time, .1)

        # Pause stopwatch
        elif self.paused:
            Clock.unschedule(self.increment_time)
            print("!!", self.time)  # To make it easier to see if stopwatch actually resumes where it left off
            print('unscheduled')  # Just to confirm and to make it a bit easier to see

        # resume stopwatch
        elif not self.paused:
            Clock.schedule_interval(self.increment_time, .1)


class PopupMenu(Popup):
    example = ExampleWidget()


class MyApp(App):
    ExampleWidget = ExampleWidget()

    def build(self):
        return ExampleWidget()


MyApp().run()

.kv file: .kv 文件:

#:import Factory kivy.factory.Factory
<PopupMenu@Popup>
    auto_dismiss: False
    size_hint_y: .8
    size_hint_x: .9
    title: 'Pause'
    example: app.ExampleWidget

    BoxLayout:
        Button:
            text: 'resume'
            on_press: root.example.paused = False
            on_release: root.dismiss(); root.example.stop_start_or_pause()
            size: self.size

<ExampleWidget>:
    GridLayout:
        col: 2
        rows: 3
        size: root.size
        Button:
            text: 'start'
            size: self.size
            on_press: root.stop = False; root.stop_start_or_pause()
        Button:
            text: 'stop'
            size: self.size
            on_press: root.stop = True; root.stop_start_or_pause()
        Button:
            text: 'Pause menu'
            size: self.size
            on_press: root.paused = True
            on_release: Factory.PopupMenu().open(); root.stop_start_or_pause()
        Label:
            text: str(round(root.time))
            size: self.size

I tried making a function and using Clock.schedule.interval() to keep checking if paused == True, but it keeps returning:我尝试制作 function 并使用 Clock.schedule.interval() 继续检查是否暂停 == True,但它一直返回:

AttributeError: 'float' object has no attribute 'stopped'

This didn't seem like efficient solution anyways, so I didn't want to spend too much time on this function.无论如何,这似乎不是有效的解决方案,所以我不想在这个 function 上花费太多时间。 I also tried to find 'stupid' mistakes (Ie ',' instead of '.') but that was before I realised that the resume button returned a 'second' stopwatch instead of updating the one I actually wanted to use.我还试图找出“愚蠢”的错误(即“,”而不是“。”),但那是在我意识到恢复按钮返回“第二”秒表而不是更新我真正想要使用的秒表之前。

I hope that someone can help, and that my question is clear.我希望有人可以提供帮助,并且我的问题很清楚。 English is not my first language so I sometimes have a hard time finding the best way to explain/ask questions.英语不是我的第一语言,所以我有时很难找到解释/提问的最佳方式。

Thank you in advance!先感谢您!

If I understand your question, the problem is with your MyApp class:如果我理解您的问题,那么问题出在您的MyApp class 上:

class MyApp(App):
    ExampleWidget = ExampleWidget()

    def build(self):
        return ExampleWidget()

This code is creating two instances of ExampleWidget .此代码正在创建ExampleWidget的两个实例。 One is returned in the build() method, and one is saved as the ExampleWidget attribute of MyApp .一个在build()方法中返回,一个保存为MyAppExampleWidget属性。 Now, when you use the ExampleWidget attribute of MyApp , you are not referencing the ExampleWidget that is the root of your GUI, so it has no effect on what appears on the screen.现在,当您使用MyAppExampleWidget属性时,您没有引用作为 GUI 根目录的ExampleWidget ,因此它对屏幕上显示的内容没有影响。 The fix is to just creat a single instance of ExampleWidget , like this:修复方法是只创建一个ExampleWidget实例,如下所示:

class MyApp(App):
    ExampleWidget = ExampleWidget()

    def build(self):
        return self.ExampleWidget

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM