Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/user-interface/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 在Kivy中构建简单的进度条或加载动画?_Python_User Interface_Events_Kivy - Fatal编程技术网

Python 在Kivy中构建简单的进度条或加载动画?

Python 在Kivy中构建简单的进度条或加载动画?,python,user-interface,events,kivy,Python,User Interface,Events,Kivy,我正在为我开发的cmd行实用程序编写一个KivyUI。一切正常,但有些进程可能需要几秒钟到几分钟的时间来处理,我想向用户提供一些进程正在运行的指示。理想情况下,这将是一个纺车或加载条或其他形式,但即使我可以更新我的显示,向用户显示一个进程正在运行,这将比我现在拥有的要好 当前,用户在主UI中按下一个按钮。这会弹出一个弹出窗口,向用户验证一些关键信息,如果用户对这些选项满意,他们会按“运行”按钮。我试着打开一个新的弹出窗口,告诉他们进程正在运行,但是因为直到进程完成显示才会更新,所以这不起作用 我

我正在为我开发的cmd行实用程序编写一个KivyUI。一切正常,但有些进程可能需要几秒钟到几分钟的时间来处理,我想向用户提供一些进程正在运行的指示。理想情况下,这将是一个纺车或加载条或其他形式,但即使我可以更新我的显示,向用户显示一个进程正在运行,这将比我现在拥有的要好

当前,用户在主UI中按下一个按钮。这会弹出一个弹出窗口,向用户验证一些关键信息,如果用户对这些选项满意,他们会按“运行”按钮。我试着打开一个新的弹出窗口,告诉他们进程正在运行,但是因为直到进程完成显示才会更新,所以这不起作用


我有很多编码经验,但主要是在数学和工程方面,因此我对UI的设计非常陌生,必须处理事件和线程。非常感谢您提供一个简单的自包含示例。

我最近正在解决您描述的问题:
显示在流程完成之前不会更新。

下面是我在#Kivy IRC频道@andy_s的帮助下得到的一个完整示例:

My main.py:

from kivy.app import App
from kivy.uix.popup import Popup
from kivy.factory import Factory
from kivy.properties import ObjectProperty
from kivy.clock import Clock

import time, threading

class PopupBox(Popup):
    pop_up_text = ObjectProperty()
    def update_pop_up_text(self, p_message):
        self.pop_up_text.text = p_message

class ExampleApp(App):
    def show_popup(self):
        self.pop_up = Factory.PopupBox()
        self.pop_up.update_pop_up_text('Running some task...')
        self.pop_up.open()

    def process_button_click(self):
        # Open the pop up
        self.show_popup()

        # Call some method that may take a while to run.
        # I'm using a thread to simulate this
        mythread = threading.Thread(target=self.something_that_takes_5_seconds_to_run)
        mythread.start()

    def something_that_takes_5_seconds_to_run(self):
        thistime = time.time() 
        while thistime + 5 > time.time(): # 5 seconds
            time.sleep(1)

        # Once the long running task is done, close the pop up.
        self.pop_up.dismiss()

if __name__ == "__main__":
    ExampleApp().run()
我的例子是.kv:

AnchorLayout:
    anchor_x: 'center'
    anchor_y: 'center'
    Button:
        height: 40
        width: 100
        size_hint: (None, None)
        text: 'Click Me'
        on_press: app.process_button_click()

<PopupBox>:
    pop_up_text: _pop_up_text
    size_hint: .5, .5
    auto_dismiss: True
    title: 'Status'   

    BoxLayout:
        orientation: "vertical"
        Label:
            id: _pop_up_text
            text: ''
锚点布局:
主播:中锋
主播:“中心”
按钮:
身高:40
宽度:100
大小提示:(无,无)
文本:“单击我”
按下:应用程序处理按钮点击()
:
弹出文本:\弹出文本
大小提示:.5,.5
自动排除:正确
标题:“状态”
盒子布局:
方向:“垂直”
标签:
id:\u弹出\u文本
文本:“”

如果运行此示例,可以单击
单击我
按钮,该按钮将以模式/弹出窗口的形式打开“进度条”。此弹出窗口将保持打开状态5秒钟,而不会阻塞主窗口。5秒后,弹出窗口将自动关闭。

我处理过类似的问题,但创建新线程并没有做到这一点。我不得不使用
Clock.schedule\u once(new\u func)
函数。它将函数调用安排到下一帧,因此它几乎会在回调结束后立即运行。

我有这个问题,但发现这里的讨论有点超出我的理解

我看了很多答案,但在我进一步研究线程模块之前,没有任何意义。Kivy在discord上的支持频道也非常有帮助,所以为他们提供了道具

我的解决方法是创建一个加载屏幕。对于同样需要简单可复制代码片段的人,我将在此附上代码:

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.recycleview import RecycleView
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import ObjectProperty, ListProperty, StringProperty, 
NumericProperty
import threading
import time
from kivy.clock import mainthread


class WindowManager(ScreenManager):
    pass

class WelcomeWindow(Screen):

    def generateData(self):
        data = []
        for i in range (100):
            #print(i)
            data.append(i)
        time.sleep(3)
        self.set_screen()
        return data

def executeFunc(self):
    self.manager.current = 'Loading' # Here is where I have tried to move to loading screen while func runs
    t1 = threading.Thread(target=self.generateData)# Here is where I have tried to thread the function
    t1.start()
    #t1.join() #Here is where I have tried to wait until func finished before changing screen
    #self.manager.current = 'Final'

@mainthread
def set_screen(self):
    self.manager.current = 'Final'



class LoadingWindow(Screen):
    pass

class FinalWindow(Screen):
    pass

KV = '''
WindowManager:
    WelcomeWindow:
    LoadingWindow:
    FinalWindow:

<WelcomeWindow>:
    name:'Welcome'
    BoxLayout:
        Label:
            text: "JUST SOME TEXT"
        Button:
            text: "Generate Data"
            font_size: sp(30)
            size_hint: .4,.4
            on_release:
                root.executeFunc()
                #app.root.current = "Loading"
                root.manager.transition.direction = "left"

<LoadingWindow>:
    name: 'Loading'
    BoxLayout:
        Label: 
            text: "LOADING SCREEN"
        Button:
            text: "Go Back"
            on_release:
                app.root.current = "Welcome"
                root.manager.transition.direction = "right"
                
<FinalWindow>:
    name: 'Final'
    BoxLayout:
        Label: 
            text: "FINISHED"
'''''

class TestApp(App):
    def build(self):
        return Builder.load_string(KV)

TestApp().run()
从kivy.app导入应用
从kivy.lang导入生成器
从kivy.uix.recycleview导入recycleview
从kivy.uix.screenmanager导入screenmanager,屏幕
从kivy.properties导入ObjectProperty、ListProperty、StringProperty、,
数值性质
导入线程
导入时间
从kivy.clock导入主线程
类WindowManager(屏幕管理器):
通过
类窗口(屏幕):
def生成数据(自身):
数据=[]
对于范围(100)内的i:
#印刷品(一)
数据追加(一)
时间。睡眠(3)
self.set_屏幕()
返回数据
def executeFunc(自身):
self.manager.current='Loading'#这里是我在func运行时尝试移动到加载屏幕的地方
t1=threading.Thread(target=self.generateData)#这里是我尝试对函数执行线程的地方
t1.start()
#t1.join()#在这里,我试图等到func完成后再更改屏幕
#self.manager.current='Final'
@主线
def设置屏幕(自身):
self.manager.current='Final'
类加载窗口(屏幕):
通过
课程最终窗口(屏幕):
通过
KV='''
WindowManager:
欢迎光临:
加载窗口:
最后窗口:
:
姓名:'欢迎'
盒子布局:
标签:
文字:“只是一些文字”
按钮:
文本:“生成数据”
字体大小:sp(30)
大小提示:.4,.4
发布时:
root.executeFunc()
#app.root.current=“正在加载”
root.manager.transition.direction=“左”
:
名称:“正在加载”
盒子布局:
标签:
文本:“加载屏幕”
按钮:
文本:“返回”
发布时:
app.root.current=“欢迎”
root.manager.transition.direction=“右”
:
名称:“决赛”
盒子布局:
标签:
正文:“已完成”
'''''
类TestApp(应用程序):
def生成(自):
返回生成器。加载字符串(KV)
TestApp().run()

请参阅。也许你可以在自己的应用程序中使用它。谢谢@Dirty Penguin的建议。我一直在玩这个,从线程开始,有一个非常奇怪的问题。当我点击应用程序内运行按钮时,我不会调用我的函数,而是调用一个启动程序,它会生成一个“运行”弹出窗口,并用我的函数启动一个线程。问题是,当作为线程运行时,函数会做一些奇怪的事情。基本上,我的函数基于csv生成一个按钮表,当作为线程运行时,其中一些按钮是白色的,不可点击。每次都有不同的按钮,如果我不将其作为单独的线程运行,它就会消失。想法?原来这些奇怪的按钮是可点击的,它们只是看起来与我表格中的其他按钮有莫名其妙的不同。通常是1个或4个按钮(约60个)完成此操作。所有其他按钮都有默认的填充颜色,但这些奇怪的按钮有白色填充,单击时不会高亮显示。我能判断它们是否可点击的唯一方法是将打印绑定到它们上。你应该只在主线程中更改小部件。