基维 |直到程序结束屏幕才会改变

Posted

技术标签:

【中文标题】基维 |直到程序结束屏幕才会改变【英文标题】:Kivy | Screen won't change until the end of the program 【发布时间】:2019-08-22 22:54:48 【问题描述】:

我正在尝试使用 Python 并使用 Kivy 作为 GUI 创建一个工具。当用户运行该工具时,我希望显示一个进度条。我通过使用 Kivy 屏幕实现了这一点。我有一个主菜单屏幕、文件选择器弹出窗口和一个进度条。

屏幕工作正常,但是只有在方法的其余部分完成后,进度条(屏幕)才会从主菜单更改。即使我已经告诉屏幕改变。这会破坏进度条的点,因为当屏幕最终更改时,该工具已经完成运行。

我似乎无法解决这个问题。我尝试使用弹出窗口,但遇到了同样的问题。通过插入一些断点并使用调试器,我可以看到屏幕管理器已经实现了更改,但直到程序结束才更改屏幕。

main.py

#When run button is pressed the run method is called
import sys
import time

from kivy.app import App
from kivy.lang import Builder
from kivy.properties import ObjectProperty
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.popup import Popup
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
from kivy.properties import ObjectProperty
from kivy.uix.popup import Popup
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
import os
from kivy.uix.screenmanager import ScreenManager, Screen



class MainScreen(Screen):
    loadfile = ObjectProperty(None)
    text_input = ObjectProperty(None)

    # Dissmiss Popup aka cancel button
    def dismiss_popup(self):
        self._popup.dismiss()

    # File Browser
    def show_load(self):
        content = LoadDialog(load=self.load, cancel=self.dismiss_popup)
        self._popup = Popup(title="Select Disk Image", content=content, size_hint=(0.9, 0.9))
        self._popup.open()

    # Select file function
    def load(self, path, filename):
        with open(os.path.join(path, filename[0])):
            global diskimage
            diskimage = filename[0]

    # When the run button is clicked
    # Makes sure they have to select a file before pressing run
    def run(self):
        if diskimage is None:
            "Please Select a Disk Image"
        else:
            print("Initialising")
            # calling BulkExrtaor class
            print("screen currently set to:", self.manager.current)

            self.manager.current = 'progressbar'

            print("screen currently set to:", self.manager.current)

            BulkExtractor().bulkextractor_run()
            #p1.start()
            print(self.manager.current)
            print("changed?")
    def startBE(self):
        BulkExtractor().bulkextractor_run()


class AnotherScreen(Screen):

    pass


class ScreenManagement(ScreenManager):
    pass

class GUI_RUN(App):

    def build(self):
        return presentation

class BulkExtractor(MainScreen):

    #Bulk Extractor run method
    def bulkextractor_run(self):
         print("File Path to file", "\"" + diskimage + "\"")

         #Runs Bulk Extractor
         #command im trying to run
         # os.system("%Programdata%\\bulk_extractor64.exe -o output ""\"" + diskimage + "\"")

        #Using sleep as a test instead of trying to run the actual command above
         print("Still hasn't changed")
         time.sleep(20)
         print("Still hasn't changed")

         print("Program Finished")

class Progressbar(ScreenManager):
    pass

class LoadDialog(FloatLayout):
    load = ObjectProperty(None)
    cancel = ObjectProperty(None)

presentation = Builder.load_file("main.kv")

if __name__ == "__main__":
    GUI_RUN().run()

Main.kv

ScreenManagement:
    MainScreen:
    AnotherScreen:

<MainScreen>:
    name: 'main'
    FloatLayout:
        Label:
            font_size: 50
            size_hint: 0.3, 0.2
            text: "FD"
            pos_hint: "right": 0.65,'top':1

        Button:
            font_size: 25
            size_hint: 0.3, 0.2
            text: "Select Disk Image"
            pos_hint: "right": 0.65,'top':0.5
            on_press: root.show_load()

        Button:
            font_size: 25
            size_hint: 0.3, 0.2
            text: "Run"
            pos_hint: "right": 0.65,'top':0.3
            on_press: root.run()

<LoadDialog>:
    BoxLayout:
        size: root.size
        pos: root.pos
        orientation: "vertical"
        FileChooserIconView:
            id: filechooser
            path: "C:/"

        BoxLayout:
            size_hint_y: None
            height: 30
            Button:
                text: "Cancel"
                on_release: root.cancel()

            Button:
                text: "Select"
                on_press: root.load(filechooser.path, filechooser.selection)
                on_release: root.cancel()

<AnotherScreen>:
    name: 'progressbar'
    Label:
        text: 'Progress: %'.format(int(pb.value))
        size_hint_y: None
        pos: 10, 400
        font_size: 30
    ProgressBar:
        id: pb
        min: -100
        max: 100
        value: 0
        size_hint: 0.5 , 1.0
        width: 200
        pos : 200, 70

    Button:
        on_release: app.root.current = 'main'
        text: 'Cancel'
        size_hint_x: .3
        size_hint_y: .1
        pos: 290, 190
        font_size:

处理类/方法后,画面变化....

谁能告诉我我做错了什么?

要对此进行测试,请运行代码并选择系统上的任何文件并点击运行。

【问题讨论】:

使用您提供的代码,很难帮助您。请提供更多代码。 这段代码会在'progressbar产生语法错误 ikoim 我已经编辑了帖子以显示完整的代码。谢谢。 【参考方案1】:

您有一个常见问题是您的bulkextractor_run() 方法在主线程上运行,从而使主线程保持忙碌状态,因此它无法更新任何GUI 元素。要使其正常工作,请在不同的线程中运行该方法:

def run(self):
    if diskimage is None:
        "Please Select a Disk Image"
    else:
        print("Initialising")
        # calling BulkExrtaor class
        print("screen currently set to:", self.manager.current)

        self.manager.current = 'progressbar'

        print("screen currently set to:", self.manager.current)

        Thread(target=BulkExtractor().bulkextractor_run).start()

        print(self.manager.current)
        print("changed?")

然后,在您的bulkextractor_run() 方法中,您需要在主线程上执行ProgressBar 更新,可能使用Clock.schedule_once(),如下所示:

class BulkExtractor(MainScreen):


    #Bulk Extractor run method
    def bulkextractor_run(self):
         print("File Path to file", "\"" + diskimage + "\"")

         #Runs Bulk Extractor
         #command im trying to run
         # os.system("%Programdata%\\bulk_extractor64.exe -o output ""\"" + diskimage + "\"")

        #Using sleep as a test instead of trying to run the actual command above
         for i in range(101):
             time.sleep(0.1)
             Clock.schedule_once(partial(self.update_progressBar, i))

         print("Program Finished")

    def update_progressBar(self, val, dt):
        presentation.get_screen('progressbar').ids.pb.value = val

【讨论】:

谢谢@John Anderson,这解决了我的问题!最近几天一直坚持这个.... @ikolim 发布的答案提到了您应该注意的几个问题。

以上是关于基维 |直到程序结束屏幕才会改变的主要内容,如果未能解决你的问题,请参考以下文章

运行一个循环,直到 UIPanGestureRecognizer 结束

带有睡眠循环的PHP直到循环结束才更新数据库

如果我在另一个屏幕中,我如何获取屏幕的 MDTextField(或数据“登录”)的文本。 (基维/基维MD/Python)

基维屏幕。我必须用超级初始化吗?

shell调用mapreduce结束后无法获取结束状态

MySqlClient EndOfStreamException:尝试读取流结束时发生致命错误