Киви |Экран не изменится до конца программы - PullRequest
0 голосов
/ 01 апреля 2019

Я пытаюсь создать инструмент, использующий Python и использующий Kivy в качестве GUI.Когда пользователь запускает инструмент, я хочу отображать индикатор выполнения.Я добился этого с помощью экранов Kivy.У меня есть экран главного меню, всплывающее окно выбора файла и индикатор выполнения.

Экраны работают нормально, однако индикатор выполнения (экран) из главного меню будет меняться только после завершения остальной части метода.Даже если я сказал экран, чтобы изменить.Это побеждает точку индикатора выполнения, поскольку инструмент уже завершил работу, когда экран, наконец, меняется.

Я не могу обойти эту проблему.Я пытался использовать всплывающие окна, но у меня возникла та же проблема.Вставив несколько точек останова и используя отладчик, я вижу, что Screen Manager осознал изменение, но не меняет экраны до конца программы.

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:

После обработки класса / метода экран меняется ....

Может кто-нибудь сказать мне, что я делаю не так?

Чтобы проверить это, запустите код, выберите любой файл в вашей системе и нажмите Run.

1 Ответ

0 голосов
/ 02 апреля 2019

У вас есть общая проблема в том, что ваш метод 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
...