Emmanuel Nabi
Emmanuel Nabi

Reputation: 155

kivy popup displaying at the end of a running process

For some process in my app, I use the internet to acquire some data. So for those processed I want a simple popup box(with a text Loading...) to appear at the begining of the process, but when I ran the test code, I observed that the popup box displays at the end of the process rather than at the begining of the process which makes it useless. Here is the test code I am using. Your help is appreciated, thanks.

class ScreenManagement(ScreenManager):
    def popup(self):
        self.pop_up=Popup(title='Loading...')
        self.pop_up.open()

    def popup_done(self):
        self.pop_up.dismiss()

    def ite(self):
        for i in range(100):
            App.get_running_app().root.current='second'
            return i

    def thread_it(self,fx):
        self.popup()
        mythread = threading.Thread(target=fx)
        mythread.start()

    def ite(self,num):
        for i in range(num):
            txt=str(i)*40
            self.ids.lbl.text=txt
            print txt
            #if i==num-1: #this is not working
             #   self.popup_done()

class labelApp(App):

    def build(self):
        pass

labelApp().run()

.kv file

ScreenManagement:
    Screen:
        BoxLayout:
            Button:
                #on_press:root.popup()
                #on_release:root.popup_done()
                on_press:root.thread_it(root.ite(40000))
                on_press:root.current='second'

    Screen:
        name:'second'
        BoxLayout:
            Label:
                id:lbl
                text: 'hello'

Upvotes: 1

Views: 707

Answers (1)

Peter Badida
Peter Badida

Reputation: 12169

The problem is with your ScreenManagement.ite() method. It doesn't run in thread and you've already noticed that anything that could compete with Kivy's main loop and doesn't run in Thread will freeze the main loop. Kivy has Clock which might interest you too.

For this exact code however you'll need partial, which will freeze a function in time and return a thing you can pass as argument, so that it wouldn't be executed in-place where you want to add it as an argument to a thread function (e.g. if ite() means executing, partial will remove those brackets and let Thread add them when it's necessary)

Thread(target=fx) means after passing the ite() method basically this:

Thread(target=root.ite(40000))

i.e. runs that thing in-place and as ite() method doesn't return anything, it'll do this:

# freeze main loop
# after done, call Thread
Thread(target=None)

and starts it. So you freeze your main loop and after the ite() ends, the Popup gets its turn to show up. Let's fix it with partial:

#:import partial functools.partial
<ScreenManagement>:
    Screen:
        BoxLayout:
            Button:
                #on_press:root.popup()
                #on_release:root.popup_done()
                on_press: root.thread_it(partial(root.ite,400))
                on_press: root.current='second'

Upvotes: 2

Related Questions