【问题标题】:Kivy screen becomes unresponsiveKivy 屏幕变得无响应
【发布时间】:2021-05-13 01:04:46
【问题描述】:

从 Pygame 切换后,我正在 Kivy 中制作应用程序(Kivy 更适合这样的应用程序),我似乎遇到了与以前相同的问题。一旦通过按下按钮调用函数,它就必须运行它的过程。在此之前单击屏幕上的任意位置将导致屏幕无响应。我希望用户能够在中途停下来。我也分配了一个“stop_function”功能(它将条件“function_stop”从主要功能更改为技术上阻止它执行)到.kv文件中的一个“停止”按钮,但我无法点击它。

还有另一个问题。该功能旨在以随机时间间隔播放声音,但它只播放一次声音。当我通过打印语句检查它时,循环仍然循环,但声音没有播放。

我希望有人可以提供帮助。这是我的代码的 sn-p:

类 MyApp(App): 定义构建(自我): 返回kv

def play_tech(self, new_dict):
    technique = (random.choice(session_list))
    print(technique)
    new_dict[technique].play()

def in_session(self):
    function_stop = False
    now = time.time()
    global timer
    timer = 0
    while timer < int(session_time) and function_stop == False:
        play_tech(cog_dict)
        end = time.time()
        timer = round(end - now)
        print(timer)
        time.sleep((cooldown + random.randint(0, 4)))
    return

def stop_function(self):
    function_stop = True
    print

以及.kv文件的相应部分:

FloatLayout:

    Button:
        text: "Back"
        font_size: 0.4 * self.height
        size_hint: 0.1, 0.08
        pos_hint: {"x": 0.45, "y": 0.05}
        on_release:
            app.root.current = "cog"
            root.manager.transition.direction = "right"

    Button:
        text: "Start"
        size_hint: 0.2, 0.2
        pos_hint: { "x": 0.2, "y": 0.1}
        on_release:
            app.in_session()

    Button:
        text: "Stop"
        size_hint: 0.2, 0.2
        pos_hint: { "x": 0.6, "y": 0.1}
        on_release:
            app.stop_function()

我希望有人可以对此有所了解。如果您需要完整代码,请告诉我。

非常感谢看到这个的人。

【问题讨论】:

  • 您的 in_seession() 方法在主线程上运行,不允许 kivy 响应事件(如按钮按下)。只需修改您的代码以在另一个线程上运行in_session()
  • 非常感谢您的回复。这是有道理的,尽管我似乎无法让它发挥作用。我是否将方法留在原处并仅创建一个在执行 in_session() 时将创建新线程的方法?比如:th = Thread(target=in_session, args=()) th.daemon = True th.start()
  • 再次感谢您。我设法为该函数创建了另一个线程,它运行良好,并且我能够在它执行时按下所有按钮。随时发布此评论作为答案。然而,我还有一个问题。函数执行期间播放的声音被缩短。知道是什么原因造成的吗?我在任何地方都找不到任何解决方案的迹象。

标签: python audio kivy


【解决方案1】:

问题在于 while 循环以及其中的 sleep() 函数。

在 Kivy 中,所有内容、事件、函数等都在一个主循环中运行,该循环在应用的整个生命周期内重复运行,在每次迭代中接收输入并执行许多其他操作。

当您调用 in_session() 方法时,循环将保持在该迭代中,直到 while 循环完成。这是一个问题,因为 Kivy 无法接收输入,或者更确切地说,在该迭代中仍无法执行任何操作,因此应用程序变得无响应。

要解决此问题,请使用 Clock.schedule_interval()、Clock.schedule_once() 或 Clock.create_trigger() 函数。
例如,在我的例子中,我使用了 Clock.schedule_interval() ;

  1. 使用 Clock.schedule_interval() 方法重复调用一个函数(在我的例子中,一个 RootLayout() 方法, on_session_begin() ),该函数将调用 play_tech() 方法和您想要的其他进程。
self.event = Clock.schedule_interval(self.root_layout.on_session_begin, 1./60.)
  1. 然后在 stop_function() 方法中,通过使用停止 on_session_begin() 调用;
self.event.cancel()

这是我使用的代码;

from kivy.app import App
from kivy.lang.builder import Builder
from kivy.uix.widget import Widget
from kivy.uix.floatlayout import FloatLayout
from kivy.properties import StringProperty
from kivy.clock import Clock
import random

kv = '''
<RootFloatLayout>:

    Label:
        text: root.label_string

    Button:
        text: "Back"
        font_size: 0.4 * self.height
        size_hint: 0.1, 0.08
        pos_hint: {"x": 0.45, "y": 0.05}
        # on_release:
        #     app.root.current = "cog"
        #     root.manager.transition.direction = "right"

    Button:
        text: "Start"
        size_hint: 0.2, 0.2
        pos_hint: { "x": 0.2, "y": 0.1}
        on_release:
            app.in_session()

    Button:
        text: "Stop"
        size_hint: 0.2, 0.2
        pos_hint: { "x": 0.6, "y": 0.1}
        on_release:
            app.stop_function()
    
'''

Builder.load_string(kv)

class RootFloatLayout(FloatLayout):

    label_string = StringProperty('Hello World!')

    def play_tech(self):
        # this is my way of randomizing ,
        #  make one that matches your liking by studying the random() built in Class
        #  or make your own !
        sounds = ['Ding Dong','Bird Chirp','Buzzz','Whistle']
        if random.randint(1,200) == 2:
            self.label_string = "Sound: "+sounds[random.randint(0,3)]
    
    def on_session_begin(self,dt):
        # place all the activities you want to run when on_session() method is called here
        self.play_tech()

        # to stop the event when the on_session() method has done its job,
        # return False  

class StackOverFLow(App):
    def build(self):
        self.root_layout = RootFloatLayout()
        return self.root_layout
    
    def in_session(self):
        # creates a Clock based event that runs the on_session_begin () once (1) every 60 seconds
        self.root_layout.label_string = "Session is on!"
        self.event = Clock.schedule_interval(self.root.on_session_begin, 1./60.)
        

    def stop_function(self):
        # stops calling the on_session_begin() method, even midway
        self.root_layout.label_string = "Stopped!"
        self.event.cancel()

if __name__ == '__main__':
    StackOverFLow().run()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多