如何在流程完成之前显示 "please wait gif" 图片

how can I show "please wait gif" image before the process is complete

我想在 ListApp() class 进程完成之前显示来自 img() class 的“请稍候 gif”图像,然后在 class完成后应该会显示ListApp的画面。

我正在尝试以下代码,但它没有启动 ListApp() 的进程class

run1.py 文件

from kivy.lang import Builder
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty
from Option import OptionApp
import sys, time, threading
from kivy.uix.screenmanager import ScreenManager, Screen
from datetime import datetime
import pandas_datareader.data as web
import pandas as pd
from kivymd.uix.screen import Screen
from kivymd.uix.list import MDList,ThreeLineListItem,ThreeLineAvatarIconListItem
from kivymd.uix.list import IconLeftWidget,ImageLeftWidget
from kivy.uix.scrollview import ScrollView
from kivy.uix.button import Button
from kivymd.app import MDApp
from kivy.app import App
from kivy.properties import ObjectProperty
import csv
from os import path
from kivy.uix.image import Image
from kivy.app import App
from kivy.uix.textinput import TextInput
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.properties import NumericProperty, ListProperty, BooleanProperty, ObjectProperty, StringProperty
from kivy.uix.recycleview import RecycleView
from kivy.uix.recyclegridlayout import RecycleGridLayout
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.label import Label
from kivy.uix.recycleboxlayout import RecycleBoxLayout
from kivy.uix.behaviors import FocusBehavior
from kivy.uix.recycleview.layout import LayoutSelectionBehavior
import pandas as pd

kv = Builder.load_file("run1.kv")




class SelectableRecycleBoxLayout(FocusBehavior, LayoutSelectionBehavior,
                                 RecycleBoxLayout):
    ''' Adds selection and focus behaviour to the view. '''


class SelectableLabel(RecycleDataViewBehavior, Label):
    ''' Add selection support to the Label '''
    index = None
    selected = BooleanProperty(False)
    selectable = BooleanProperty(True)
    txt_input1 = ObjectProperty(None)
    txt_input = ObjectProperty(None)

    def refresh_view_attrs(self, rv, index, data):
        ''' Catch and handle the view changes '''
        self.index = index
        return super(SelectableLabel, self).refresh_view_attrs(
            rv, index, data)

    def on_touch_down(self, touch):
        ''' Add selection on touch down '''
        if super(SelectableLabel, self).on_touch_down(touch):
            return True
        if self.collide_point(*touch.pos) and self.selectable:
            return self.parent.select_with_touch(self.index, touch)

    def apply_selection(self, rv, index, is_selected):

        ''' Respond to the selection of items in the view. '''

        self.selected = is_selected
        if is_selected:

            # self.root.ids.txt_input1.text = str(rv.data[index].get("text"))
            App.get_running_app().root.widget_1.ids.txt_input1.text = str(rv.data[index].get("text"))

class RV(RecycleView):
    def __init__(self, **kwargs):
        super(RV, self).__init__(**kwargs)


class DropDownWidget(BoxLayout):
    txt_input = ObjectProperty()
    rv = ObjectProperty()
    txt_input1 = ObjectProperty()


class MyTextInput(TextInput):
    txt_input = ObjectProperty()
    txt_input1 = ObjectProperty(None)
    flt_list = ObjectProperty()
    word_list = ListProperty()
    # this is the variable storing the number to which the look-up will start
    starting_no = NumericProperty(3)
    suggestion_text = ''

    def __init__(self, **kwargs):
        super(MyTextInput, self).__init__(**kwargs)

    def on_text(self, instance, value):
        # find all the occurrence of the word
        self.parent.ids.rv.data = []
        matches = [self.word_list[i] for i in range(len(self.word_list)) if
                   self.word_list[i][:self.starting_no] == value[:self.starting_no]]
        # display the data in the recycleview
        display_data = []
        for i in matches:
            display_data.append({'text': i})
        self.parent.ids.rv.data = display_data
        # ensure the size is okay
        if len(matches) <= 10:
            self.parent.height = (50 + (len(matches) * 20))
        else:
            self.parent.height = 240

    def keyboard_on_key_down(self, window, keycode, text, modifiers):
        if self.suggestion_text and keycode[1] == 'tab':
            self.insert_text(self.suggestion_text + ' ')
            return True
        return super(MyTextInput, self).keyboard_on_key_down(window, keycode, text, modifiers)


class Body(Screen):
    def __init__(self, **kwargs):

        super(Body, self).__init__(**kwargs)
        f = pd.read_csv("stoploss.csv")
        fl = len(f.index)
        file = pd.DataFrame(f, columns=['Stock Symbol', 'Purchase Price', 'Stock Name', 'Stop Loss(%)'])
        j = 0
        wl = []
        for i in range(fl):
            for index in range(1):
                columnSeriesObj = file.iloc[:, 2]
                # pp = iter(columnSeriesObj.values)
                # pp1 = next(pp)
                # print(pp1)

                wl.append(columnSeriesObj.values[i])

        tp = tuple(wl)
        print(str(tp))


        self.widget_1 = DropDownWidget(pos_hint={'center_x': .5, 'center_y': .5},
                                       size_hint=(None, None), size=(600, 60))
        self.widget_1.ids.txt_input.word_list = wl
        self.widget_1.ids.txt_input.starting_no = 3

        self.add_widget(self.widget_1)
    





class signin(Screen):

    user_name = ObjectProperty(None)

    def btn(self):

        username = self.user_name.text
        print(username)
        sm.current = 'option_screen'

class option(Screen):

    def btn_addstock(self):
        sm.current = 'body_screen'

    def btn_stoplosslist(self):
        sm.canvas.clear()
        sm.current = 'Stoploss_ip'







class stockinput(Screen):
    stock_name = ObjectProperty(None)
    stock_symbol = ObjectProperty(None)
    purchase_price = ObjectProperty(None)
    stop_loss = ObjectProperty(None)


    def btn(self):
        end = datetime.today().date()
        start = end.year - 10
        start = datetime(start, datetime.today().month, datetime.today().day).date()
        uname = input("Enter user name: ")
        print("Stock Name:", self.stock_name.text, "Stock Symbol:", self.stock_symbol.text)
        print("Purchase Price:",self.purchase_price.text,"Stop Loss(%):",self.stop_loss.text)

        #write data to csv file

        # if path.exists("stoploss.csv"):
        #     myFile = open('stoploss.csv', 'a')
        # else:
        #     myFile = open('stoploss.csv', 'w')
        file_name = stockinput.uname + "_stoploss.csv"
        if path.exists(file_name):
            with open(file_name, "a+", newline='')as newFile :
                fieldnames = ["Stock Name", "Stock Symbol", "Purchase Price", "Stop Loss(%)"]
                newFileWriter = csv.DictWriter(newFile, fieldnames=fieldnames)
                newFileWriter.writerow({"Stock Name" : self.stock_name.text,"Stock Symbol" : self.stock_symbol.text,"Purchase Price" : self.purchase_price.text,"Stop Loss(%)" : self.stop_loss.text})

        else:
            myFile = open(file_name, 'w+')
            myData = [["Stock Name", "Stock Symbol", "Purchase Price", "Stop Loss(%)"],[self.stock_name.text, self.stock_symbol.text, self.purchase_price.text, self.stop_loss.text]]

            with myFile:
                writer = csv.writer(myFile)
                writer.writerows(myData)

        df = web.DataReader(self.stock_symbol.text, 'yahoo', start, end,)
        print(df.tail())

        self.stock_name.text = ""
        self.stock_symbol.text = ""
        self.purchase_price.text = ""
        self.stop_loss.text = ""

f = pd.read_csv("stoploss.csv")
file = pd.DataFrame(f, columns=['Stock Symbol','Purchase Price','Stock Name','Stop Loss(%)'])


class img(Screen):
    def build(self,**kwargs):
        super(img, self).__init__(**kwargs)
        screen = self
        image = Image(source='please_wait.gif')
        screen.add_widget(image)

class ListApp(Screen):

    # def imgpr(self,**kwargs):
    #     super(ListApp, self).__init__(**kwargs)
    #
    #         time.sleep(0.1)

    # t = threading.Thread(target=imgpr)
    # t.start()
    def build(self,**kwargs):
        super(ListApp, self).__init__(**kwargs)
        flag = True


        screen = self
        # if flag:
        #
        #
        #     sm.add_widget(ListApp(name='Stoploss_ip'))


        end = datetime(2020, 12, 14)
        start = datetime(2020, 12, 14)

        btn = Button(text="Back",
                     font_size="20sp",

                     background_color=(255/255, 229/255, 204/255, 1),
                     color=(1, 1, 1, 1),
                     size=(12, 12),
                     size_hint=(.1, .05),
                     pos=(600, 500))
        btn.bind(on_press=lambda *args: setattr(sm, 'current', "option_screen"))

        scroll = ScrollView()
        list_view = MDList()


        scroll.add_widget(list_view)



        i = 0
        fl = len(file.index)
        try:
            for index in range(fl):

                for index in range(1):
                    columnSeriesObj2 = file.iloc[:, 0]

                    df = web.DataReader(columnSeriesObj2.values[i],'yahoo', start, end,retry_count=3)
                    print(df.head())
                    Objname = file.iloc[:, 2]
                    columnSeriesObj = df.iloc[:, 3]
                    columnSeriesObj1 = file.iloc[:, 1]
                    ObjStoploss = file.iloc[:, 3]

                    cp = iter(columnSeriesObj.values)
                    pp = iter(columnSeriesObj1.values)
                    pp1 = next(pp)
                    cp1 = columnSeriesObj.values[0]


                    sl = columnSeriesObj1.values[i] - (columnSeriesObj1.values[i] * (ObjStoploss.values[i]/100))


                    if cp1 <= sl:
                        image = ImageLeftWidget(source='loss.png')
                        items = ThreeLineAvatarIconListItem(text="Alert sale " + Objname.values[i], secondary_text='Close price: '+str(cp1),
                                                            tertiary_text='Stoploss: ' + str(sl))
                        items.add_widget(image)
                        list_view.add_widget(items)



                        i=i+1


                    else:
                        image = ImageLeftWidget(source='profit.jpg')
                        items = ThreeLineAvatarIconListItem(text="Chill " + Objname.values[i],
                                                            secondary_text='Close price: ' + str(cp1),
                                                            tertiary_text='Stoploss: ' + str(sl))
                        items.add_widget(image)
                        list_view.add_widget(items)


                        i=i+1
        except ConnectionAbortedError:
            print("Check your Internet connection")
        except ConnectionRefusedError:
            print("Check your Internet connection")
        except ConnectionError:
            print("Check your Internet connection")
        except ConnectionResetError:
            print("Check your Internet connection")
        except TimeoutError:
            print("Timeout!!!!...Check your Internet connection")
        except KeyError:
            pass

        except:
            print("Something went wrong")
        print("Done")

        # flag = False
        # if flag ==False:
        screen.add_widget(scroll)
        screen.add_widget(btn)
        # return screen


class WindowsManager(ScreenManager):
    pass

sm = ScreenManager()
sm.add_widget(signin(name='signin_screen'))
sm.add_widget(option(name='option_screen'))
sm.add_widget(stockinput(name='stockinput_screen'))
sm.add_widget(img(name='image_screen'))
sm.add_widget(ListApp(name='Stoploss_ip'))
sm.add_widget(Body(name='body_screen'))

class run1(MDApp):
    def build(self):
        return sm

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

run1.kv 文件

<WindowsManager>:
    signin:
    option:
    stockinput:
    ListApp:
    Body:


<Body>:
    name: 'body_screen'
    canvas.before:
        Color:
            rgba: 188/255, 143/255, 145/255, 1

        Rectangle:
            pos: self.pos
            size: self.size


<DropDownWidget>:
    id: DropDownWidget
    canvas:
        Color:
            rgba:(1, 1, 1, 1)
        Rectangle:
            # pos: self.pos
            size: self.size

    # orientation: 'vertical'
    spacing: 20
    txt_input: txt_input
    rv: rv

    txt_input1: txt_input1
    MyTextInput:
        id: txt_input1
        pos: 400,300
        size_hint_y: None
        height: 50
    MyTextInput:
        id: txt_input
        hint_text:'Enter here'
        size_hint_y: None
        height: 50
    RV:
        id: rv




<MyTextInput>:
    id: MyTextInput

    readonly: False
    multiline: False

<SelectableLabel>:

    id: SelectableLabel

    # Draw a background to indicate selection
    color: 0,0,0,1
    canvas.before:
        Color:
            rgba: (0, 0, 1, .5) if self.selected else (1, 1, 1, 1)
        Rectangle:
            # pos: self.pos
            size: self.size

<RV>:


    canvas:
        Color:
            rgba: 0,0,0,.2

        Line:
            rectangle: self.x +1 , self.y, self.width - 2, self.height -2


    bar_width: 10
    scroll_type:['bars']
    viewclass: 'SelectableLabel'
    SelectableRecycleBoxLayout:
        default_size: None, dp(20)
        default_size_hint: 1, None
        size_hint_y: None
        height: self.minimum_height
        orientation: 'vertical'
        multiselect: False
<signin>:

    canvas.before:
        Color:
            rgba: 164/255, 66/255, 220/255, 1
        Rectangle:
            pos: self.pos
            size: self.size

    name: 'signin_screen'

    user_name: user_name



    GridLayout:
        pos_hint: {'center_x': .75, 'center_y': .15}
        row_force_default : True
        row_default_height : 50
        col_force_default : True
        col_default_width : 400
        spacing: '15dp'
        cols: 1

        TextInput:
            id: user_name
            multiline:False
            size_hint: 5.0 ,.1

            hint_text: "Email_ID"

        Button:
            text:"Submit"
            font_size: 20
            color:0,0,0,1

            size_hint: .5 ,.3
            background_normal: ''
            background_color: (255/255, 153/255, 71/255, 1)
            on_press : root.btn()





        Label:
            text:"Please Do not change the Email_ID. Data will be saved as per your Email_ID"
            pos: 180,80

<option>:
    canvas.before:
        Color:
            rgba: 138/255, 104/255, 175/255, 1
        Rectangle:
            pos: self.pos
            size: self.size
    name: 'option_screen'

    GridLayout:
        pos_hint: {'center_x': .83, 'center_y': .18}
        row_force_default : True
        row_default_height : 100
        col_force_default : True
        col_default_width : 250
        spacing: '20dp'


        cols:1

        Button:
            text:"Add Stock"
            color:0,0,0,1
            font_size: 18
            size_hint: .1 ,.1
            pos: 150,150
            background_normal: ''
            background_color: (204/255, 0, 204/255, 1)

            on_press : root.manager.current = 'body_screen'

        Button:
            text:"Check Stoploss"
            color:0,0,0,1
            font_size: 18
            size_hint: .1 ,.1
            pos: 250,120
            background_normal: ''
            background_color:(127/255, 193/255, 184/255, 1)


            on_press : root.manager.current = 'Stoploss_ip'




<stockinput>:
    canvas.before:
        Color:
            rgba: 188/255, 143/255, 145/255, 1

        Rectangle:
            pos: self.pos
            size: self.size
    name: 'stockinput_screen'
    stock_name: stock_name
    stock_symbol: stock_symbol
    purchase_price: purchase_price
    stop_loss: stop_loss

    GridLayout:

        pos_hint: {'center_x': .67, 'center_y': .2}
        row_force_default : True
        row_default_height : 40
        col_force_default : True
        col_default_width : 250
        spacing: '10dp'
        cols:2



#            pos_hint: {'center_x': .53, 'center_y': .12}
#            row_force_default : True
#            row_default_height : 30
#            col_force_default : True
#            col_default_width : 250
#            spacing: '20dp'

        Label:
            text: "Stock Name: "

        TextInput:
            id: stock_name
            multiline:False

        Label:
            text: "Stock Symbol: "

        TextInput:
            id: stock_symbol
            multiline:False

        Label:
            text: "Purchase Price: "

        TextInput:
            id: purchase_price
            multiline:False

        Label:
            text: "Stop Loss(%): "

        TextInput:
            id: stop_loss
            multiline:False

        Button:
            text:"Submit"
            color:102/255, 204/255, 0, 1
            font_size:18
            background_color: (204/255, 0, 102/255, 1)
            on_press: root.btn()
        Button:
            text:"Back"
            color:0,0,0,1
            font_size:18
            background_normal: ''
            background_color: (204/255, 102/255, 0, 1)
            on_press: root.manager.current = 'option_screen'

<img>:
    name: 'image_screen'
    on_enter:root.build()

<ListApp>:

    name: 'Stoploss_ip'

    on_enter:root.build()

**更新 我尝试在 build() 方法中添加 2 行并显示图像 now.I 认为它预加载图像并将它们保存在缓存中。

class ListApp(Screen):


    def build(self):
        self.popup = Popup(title='Calculating Stoploss', content=Image(source='please_wait.gif'))
        self.profit = ImageLeftWidget(source='profit.jpg')
        self.loss = ImageLeftWidget(source='loss.png')
        self.popup.open()
        # Clock.schedule_once(partial(self.actual_build))

        threading.Thread(target=self.actual_build).start()
    def actual_build(self):

        screen = self

        end = datetime.today().date()
        start = end

        btn = Button(text="Back",
                     font_size="20sp",

                     background_color=(255/255, 229/255, 204/255, 1),
                     color=(1, 1, 1, 1),
                     size=(12, 12),
                     size_hint=(.1, .05),
                     pos=(600, 500))
        btn.bind(on_press=lambda *args: setattr(sm, 'current', "option_screen"))

        scroll = ScrollView()
        list_view = MDList()


        scroll.add_widget(list_view)



        i = 0
        fl = len(file.index)
        try:
            for index in range(fl):

                for index in range(1):
                    columnSeriesObj2 = file.iloc[:, 0]

                    df = web.DataReader(columnSeriesObj2.values[i],'yahoo', start, end,retry_count=3)
                    print(df.head())
                    Objname = file.iloc[:, 2]
                    columnSeriesObj = df.iloc[:, 3]
                    columnSeriesObj1 = file.iloc[:, 1]
                    ObjStoploss = file.iloc[:, 3]

                    cp = iter(columnSeriesObj.values)
                    pp = iter(columnSeriesObj1.values)
                    pp1 = next(pp)
                    cp1 = columnSeriesObj.values[0]


                    sl = columnSeriesObj1.values[i] - (columnSeriesObj1.values[i] * (ObjStoploss.values[i]/100))


                    if cp1 <= sl:
                        image = ImageLeftWidget(source='loss.png')
                        items = ThreeLineAvatarIconListItem(text="Alert sale " + Objname.values[i], secondary_text='Close price: '+str(cp1),
                                                            tertiary_text='Stoploss: ' + str(sl))
                        items.add_widget(image)
                        list_view.add_widget(items)



                        i=i+1


                    else:
                        image = ImageLeftWidget(source='profit.jpg')
                        items = ThreeLineAvatarIconListItem(text="Chill " + Objname.values[i],
                                                            secondary_text='Close price: ' + str(cp1),
                                                            tertiary_text='Stoploss: ' + str(sl))
                        items.add_widget(image)
                        list_view.add_widget(items)


                        i=i+1
        except ConnectionAbortedError:
            print("Check your Internet connection")
        except ConnectionRefusedError:
            print("Check your Internet connection")
        except ConnectionError:
            print("Check your Internet connection")
        except ConnectionResetError:
            print("Check your Internet connection")
        except TimeoutError:
            print("Timeout!!!!...Check your Internet connection")
        except KeyError:
            pass

        except:
            pass
            # print("Something went wrong")
        print("Done")
        # screen.add_widget(screen.scroll)
        # screen.add_widget(btn)
        
        Clock.schedule_once(partial(screen.finish_build, scroll, btn))
        
        screen.popup.dismiss()

    def finish_build(self, scroll, btn, dt):
        screen = self
        screen.add_widget(scroll)
        screen.add_widget(btn)

由于您是通过使用 on_enter 属性触发 build() 方法,因此您可以使用该方法完成您想要的。

首先,您拨打的是:

super(ListApp, self).__init__(**kwargs)

来自 build() 方法。您不应调用该 super 方法,除非是在 __init__() 方法覆盖内。所以应该删除该行。由于你还没有为ListApp编写__init__()方法,所以没有必要调用super class __init__().

我建议将您的 build() 方法重命名为 actual_build(),如下所示:

def actual_build(self, *args):

并定义一个新的 build() 方法为:

def build(self, **kwargs):
    self.popup = Popup(title='Preparing ListApp', content=Image(source='please_wait.gif', anim_delay=0.05))
    self.popup.open()
    threading.Thread(target=self.actual_build).start()

上述方法显示动画 gif,并启动 actual_build() 方法(以前名为 build())。

然后,修改actual_build()方法为:

def actual_build(self, *args):
    # super(ListApp, self).__init__(**kwargs)
    flag = True


    screen = self
    # if flag:
    #
    #
    #     sm.add_widget(ListApp(name='Stoploss_ip'))


    end = datetime(2020, 12, 14)
    start = datetime(2020, 12, 14)

    btn = Button(text="Back",
                 font_size="20sp",

                 background_color=(255/255, 229/255, 204/255, 1),
                 color=(1, 1, 1, 1),
                 size=(12, 12),
                 size_hint=(.1, .05),
                 pos=(600, 500))
    btn.bind(on_press=lambda *args: setattr(sm, 'current', "option_screen"))

    scroll = ScrollView()
    list_view = MDList()


    scroll.add_widget(list_view)



    i = 0
    fl = len(file.index)
    try:
        for index in range(fl):

            for index in range(1):
                columnSeriesObj2 = file.iloc[:, 0]

                df = web.DataReader(columnSeriesObj2.values[i],'yahoo', start, end,retry_count=3)
                print(df.head())
                Objname = file.iloc[:, 2]
                columnSeriesObj = df.iloc[:, 3]
                columnSeriesObj1 = file.iloc[:, 1]
                ObjStoploss = file.iloc[:, 3]

                cp = iter(columnSeriesObj.values)
                pp = iter(columnSeriesObj1.values)
                pp1 = next(pp)
                cp1 = columnSeriesObj.values[0]


                sl = columnSeriesObj1.values[i] - (columnSeriesObj1.values[i] * (ObjStoploss.values[i]/100))


                if cp1 <= sl:
                    image = ImageLeftWidget(source='loss.png')
                    items = ThreeLineAvatarIconListItem(text="Alert sale " + Objname.values[i], secondary_text='Close price: '+str(cp1),
                                                        tertiary_text='Stoploss: ' + str(sl))
                    items.add_widget(image)
                    list_view.add_widget(items)



                    i=i+1


                else:
                    image = ImageLeftWidget(source='profit.jpg')
                    items = ThreeLineAvatarIconListItem(text="Chill " + Objname.values[i],
                                                        secondary_text='Close price: ' + str(cp1),
                                                        tertiary_text='Stoploss: ' + str(sl))
                    items.add_widget(image)
                    list_view.add_widget(items)


                    i=i+1
    except ConnectionAbortedError:
        print("Check your Internet connection")
    except ConnectionRefusedError:
        print("Check your Internet connection")
    except ConnectionError:
        print("Check your Internet connection")
    except ConnectionResetError:
        print("Check your Internet connection")
    except TimeoutError:
        print("Timeout!!!!...Check your Internet connection")
    except KeyError:
        pass

    except:
        print("Something went wrong")

    # flag = False
    # if flag ==False:
    # screen.add_widget(scroll)
    # screen.add_widget(btn)

    # schedule the code that must be run on the main thread
    Clock.schedule_once(partial(self.finish_build, scroll, btn))

    # dismiss the animated gif
    self.popup.dismiss()

上面的 actual_build() 方法完成了原始 build() 方法所做的一切,除了对 GUI 的实际更改(必须在主线程上完成)。在此方法结束时,安排对 finish_build() 的调用,并关闭动画 gif Popup

最后,添加一个 finish_build() 方法来执行实际的 GUI 更改:

def finish_build(self, scroll, btn, dt):
    screen = self
    screen.add_widget(scroll)
    screen.add_widget(btn)

现在我实际上可以 运行 你的代码了,我有一个更新的答案。首先,一些 ListApp 屏幕可以在 kv 文件中构造为:

<ListApp>:
    name: 'Stoploss_ip'

    on_enter:root.build()

    ScrollView:
        MDList:
            id: list_view
    
    Button:
        text: "Back"
        font_size: "20sp"
        background_color: (255/255, 229/255, 204/255, 1)
        color: (1, 1, 1, 1)
        size: (12, 12)
        size_hint: (.1, .05)
        pos: (600, 500)
        on_press: root.manager.current = "option_screen"

那么ListApp class可以是:

class ListApp(Screen):
    built = BooleanProperty(False)

    def build(self):
        if self.built:
            return
        self.built = True
        self.popup = Popup(title='Calculating Stoploss', content=Image(source='please_wait.gif'))
        self.popup.open()
        threading.Thread(target=self.actual_build).start()

    def actual_build(self):
        end = datetime.today().date()
        start = end

        i = 0
        fl = len(file.index)
        try:
            for index in range(fl):

                for index in range(1):
                    columnSeriesObj2 = file.iloc[:, 0]

                    df = web.DataReader(columnSeriesObj2.values[i],'yahoo', start, end,retry_count=3)
                    print(df.head())
                    Objname = file.iloc[:, 2]
                    columnSeriesObj = df.iloc[:, 3]
                    columnSeriesObj1 = file.iloc[:, 1]
                    ObjStoploss = file.iloc[:, 3]

                    cp = iter(columnSeriesObj.values)
                    pp = iter(columnSeriesObj1.values)
                    pp1 = next(pp)
                    cp1 = columnSeriesObj.values[0]
                    sl = columnSeriesObj1.values[i] - (columnSeriesObj1.values[i] * (ObjStoploss.values[i]/100))

                    if cp1 <= sl:
                        Clock.schedule_once(partial(self.add_loss, Objname.values[i], str(cp1), str(sl)))
                        i=i+1
                    else:
                        Clock.schedule_once(partial(self.add_profit, Objname.values[i], str(cp1), str(sl)))
                        i=i+1
        except ConnectionAbortedError:
            print("Check your Internet connection")
        except ConnectionRefusedError:
            print("Check your Internet connection")
        except ConnectionError:
            print("Check your Internet connection")
        except ConnectionResetError:
            print("Check your Internet connection")
        except TimeoutError:
            print("Timeout!!!!...Check your Internet connection")
        except KeyError:
            pass

        except:
            pass
            # print("Something went wrong")
        print("Done")
        self.popup.dismiss()

    def add_loss(self, name, close_price, stop_loss, dt):
            image = ImageLeftWidget(source='loss.png')
            items = ThreeLineAvatarIconListItem(text="Alert sale " + name, secondary_text='Close price: '+close_price,
                                                tertiary_text='Stoploss: ' + stop_loss)
            items.add_widget(image)
            self.ids.list_view.add_widget(items)

    def add_profit(self, name, close_price, stop_loss, dt):
            image = ImageLeftWidget(source='profit.jpg')
            items = ThreeLineAvatarIconListItem(text="Chill " + name,
                                                secondary_text='Close price: ' + close_price,
                                                tertiary_text='Stoploss: ' + stop_loss)
            items.add_widget(image)
            self.ids.list_view.add_widget(items)

更改的主要项目是列表和后退按钮是在 'kv' 中构建的,列表的项目是使用 Clock.schedule_once() 构建的。不再需要 finish_build() 方法。

另外,请注意我添加了一个 built 属性来跟踪屏幕是否已构建,这样屏幕就不会构建多次。如果多次构建,列表中的项目将被重复添加。