【问题标题】:Screen management and loading functions in kivy PYTHONkivy PYTHON 中的屏幕管理和加载功能
【发布时间】:2019-02-15 09:29:58
【问题描述】:

所以,我正在做这个具有主屏幕和加载屏幕的 GUI。使用加载屏幕,以便用户可以在程序执行功能时看到应用程序的进度。我希望程序更改以执行功能并在执行功能后切换回主屏幕。这是我的代码的一部分,您可以使用它来运行程序。

# Imports
import kivy
from kivy.app import App    # Imports functions to build the app
from kivy.core.window import Window
from kivy.uix.screenmanager import ScreenManager, Screen, NoTransition
from kivy.uix.button import Button
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ObjectProperty, StringProperty
from kivy.uix.popup import Popup
from kivy.uix.label import Label
from kivy.uix.image import Image
import threading
import time

kivy.require('1.10.1')


def function1():
    time.sleep(5)
    print("Done")


def function2():
    time.sleep(5)
    print("Done 2")


class MainScreen(Screen, FloatLayout):  # Main Screen Class that holds every method in the Start Screen

    auction_name = " "
    default = "Select an auction"
    selected_auction = StringProperty('Select an auction')
    x_value = 450
    y_value = 500

    def change_label(self, change):  # Changes the text that shows what auction is selected

        strtst = "Selected: " + change

        if self.selected_auction == self.default and (change == "Copart" or change == "IAAI"):
            self.selected_auction = "Selected: " + change
            self.selected_auction = "Selected: " + change
        elif self.selected_auction == strtst or self.selected_auction == "Main":
            self.selected_auction = self.default
        elif change != self.selected_auction:
            if self.selected_auction == "Selected: Copart and IAAI":
                self.selected_auction = "Selected: " + change
            else:
                if change == "None":
                    self.selected_auction == "TO START, PLEASE SELECT AN AUCTION"
                else:
                    self.selected_auction = "Selected: Copart and IAAI"

    def change_screen(self):
        self.manager.current = "Loading Screen"

    t2 = threading.Thread(target=function1)
    t3 = threading.Thread(target=function2)

    def start_process(self):  # Used to start the web scraping
        if self.selected_auction == 'Selected: Copart':
            self.manager.current = "Loading Screen"
            self.t3.start()
            self.manager.current = "Results Screen"
            self.selected_auction = "Select an auction"
        elif self.selected_auction == 'Selected: IAAI':
            self.manager.current = "Loading Screen"
            self.t2.start()
            self.selected_auction = "Select an auction"
        elif self.selected_auction == 'Selected: Copart and IAAI':
            self.manager.current = "Loading Screen"
            self.t2.start()
            self.t3.start()
        else:
            self.change_label("None")


class LoadingScreen(Screen):

    def cancel(self):
        box = BoxLayout(orientation='vertical')
        padding = Label(text= "If you say yes all progress will be lost!")
        buttons = BoxLayout()
        warning = Image(source="Data/warning.png")
        yes_button = Button(text= "Yes, do cancel it.", on_release=lambda x:self.back(),
                        on_press=lambda *args: pop.dismiss(), size=(250, 120), background_color=(300, 0.5, 0, .7))
        no_button = Button(text="No, don't cancel.", on_press=lambda *args: pop.dismiss(), size=(250, 120),
                       background_color=(.25, 150, .04, 0.5))
        box.add_widget(warning)
        box.add_widget(padding)
        buttons.add_widget(yes_button)
        buttons.add_widget(no_button)
        box.add_widget(buttons)

        pop = Popup(title="Do you wish to cancel?", content=box, size_hint=(None, None), size= (800, 500))
        pop.open()


class Manager(ScreenManager):

    main_screen = ObjectProperty(None)
    loading_screen = ObjectProperty(None)


class MainApp(App):

    choice = ""
    source = StringProperty(None)

    def build(self):
        m = Manager(transition=NoTransition())
        return m


if __name__ == "__main__":
    Window.clearcolor = (.46875, .46875, .4765, 1)
    Window.size = (850, 1000)
    MainApp().run()

在主屏幕中,有一个按钮,按下该按钮应更改屏幕并执行功能,使用start_process()处理。这是我的 main.kv 文件:

#: import NoTransition kivy.uix.screenmanager.NoTransition
#: import ProgressBar kivy.uix.progressbar
#: import Widget kivy.uix.widget
#: import ListAdapter kivy.adapters.listadapter.ListAdapter
#: import ListItemButton kivy.uix.listview.ListItemButton
#: import Popup kivy.uix.popup
#: import main gui_test

<Manager>:
    id: screen_manager

    main_screen: mainS
    loading_screen: loadingS

    MainScreen:
        id: mainS
        name: "Main Screen"
        manager: screen_manager

    LoadingScreen:
        id: loadingS
        name: "Loading Screen"
        manager: screen_manager


<MainScreen>
    FloatLayout:

        # Start Button
    Button:
        on_release: root.start_process()
        text: "Start"
        font_size: 16
        size_hint: 0.6, 0.12
        pos: root.center_x - (self.width/2), root.y + self.height
        background_normal: ''
        background_down:
        background_color: .25, .75, .04, 1
        font_size: 50

    # COPART BUTTON
    Button:
        size_hint: 0.279, 0.3
        pos: root.x + (0.3 * self.width), root.top - self.height - 160
        on_press: root.change_label("Copart")

    # IAAI BUTTON
    Button:
        id: IAAI_Button
        size_hint: 0.27, 0.3
        pos: root.x + (1.7 * self.width) + 300, root.top - self.height - 160
        on_press: root.change_label("IAAI")

    Label:
        text: root.selected_auction
        font_size: 50

<LoadingScreen>
    FloatLayout:

        Button:
            text: "Cancel"
            size_hint:0.30, 0.1
            pos: root.center_x - (self.width/2), 100
            background_color: 300, 0.5, 0, .4
            on_press: root.cancel()

你对我做错了什么有什么建议吗?感谢您的帮助!

【问题讨论】:

  • 您可能需要在另一个线程中运行您的函数。否则,您的函数会占用主线程并且不允许 LoadingScreen 更新。
  • @JohnAnderson 我一直在尝试在我的程序中实现线程。我使用 MainScreen 类中的方法将屏幕更改为加载屏幕。此方法将self 作为其唯一参数。因此,当我运行程序时,我收到以下错误:TypeError: change_screen() missing 1 required positional argument: 'self'。如何在t1 = threading.Thread(target=change_screen) 中将self 作为参数传递??
  • 您不想将更改屏幕的代码放在需要在主线程上运行的另一个线程中。您应该将另一个函数放在另一个线程中。如果您发布minimal reproducible example,那么解决这个问题会更容易和更快。
  • 我在问题中添加了start_process() 函数。所以我想做的是在从 if 语句执行的所有线程完成后返回主屏幕。我试图在MainScreen 中添加一个函数change_screen(),但因为它在一个类中,所以在声明线程时我必须传递一个参数。我该如何解决这个问题??
  • 如果没有minimal reproducible example,这将变得太复杂,无法讨论。

标签: python kivy kivy-language


【解决方案1】:

这是在运行函数后返回主屏幕的一种方法。修改目标函数为:

def function1():
    time.sleep(5)
    print("Done")
    Clock.schedule_once(App.get_running_app().show_main_screen)


def function2():
    time.sleep(5)
    print("Done 2")
    Clock.schedule_once(App.get_running_app().show_main_screen)

Clock.schedule_once() 安排在主线程上运行某些东西(更改 UI 所必需的)。

并将MainApp修改为:

class MainApp(App):

    choice = ""
    source = StringProperty(None)

    def build(self):
        self.m = Manager(transition=NoTransition())  # save a reference to `Manager`
        return self.m

    def show_main_screen(self, dt):
        self.m.current = "Main Screen"  # use the saved reference to change the current screen

此外,在您的“kv”文件中,以下行:

manager: screen_manager

不需要。该属性会自动添加到每个Screen

【讨论】:

  • 嘿约翰!有用!我想从另一个类的函数中做到这一点。我怎么能这样做呢?非常感谢您的帮助!
  • 我认为您需要为此发布一个新问题。
  • 好的,谢谢您的解决方案!!先生,我非常感谢他们。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-04
  • 2022-10-13
  • 1970-01-01
  • 2019-04-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多