I'm using concurrent.futures and currently it seems that my code runs both functions as desired BUT the first pop-up won´t show until both functions finish (A problem with that is that the second function ends by first dismissing the first dialog-box and then opening the second dialog-box).

Here´s my full .py code:

from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivymd.app import MDApp
from kivymd.uix.dialog import MDDialog
import concurrent.futures

KV = '''
<Content>
    orientation: "vertical"
    spacing: -40
    
    MDSpinner:
        size_hint: None, None
        size: dp(46), dp(46)
        pos_hint: {'center_x': 0.1}
        active: True
    MDLabel:
        text: "Processing..."
        pos_hint: {'center_x': .7}

FloatLayout:

    MDFlatButton:
        text: "ALERT DIALOG"
        pos_hint: {'center_x': .5, 'center_y': .5}
        on_release: app.start()
'''


class Content(BoxLayout):
    pass

class Example(MDApp):
    dialog = None

    def build(self):
        return Builder.load_string(KV)

    def start(self):
        with concurrent.futures.ThreadPoolExecutor() as executor:
            f1 = executor.submit(self.pop_up1())
            f2 = executor.submit(self.test())


    def pop_up1(self):
        '''Displays a pop_up with a spinning wheel'''
        if not self.dialog:
            self.dialog = MDDialog(
                size_hint=(.45, None),
                auto_dismiss=True,
                type="custom",
                content_cls=Content(),
            )
            self.dialog.open()

    def test(self):
        '''Counts to 1000000 and then it closes pop_up1 and opens pop_up2'''
        for number in range(1000000):
            print(number)
        self.dismiss()
        self.pop_up2()

    def pop_up2(self):
        if not self.dialog:
            self.dialog = MDDialog(
                title="Done",
                size_hint=(.6, None),
                text="Done",

                    )
        self.dialog.open()

    def dismiss(self, *args):
        self.dialog.dismiss()


Example().run()
1

There are 1 best solutions below

3
On BEST ANSWER

A couple problems with your code. First, when you use the construct:

    with concurrent.futures.ThreadPoolExecutor() as executor:
        f1 = executor.submit(self.pop_up1())
        f2 = executor.submit(self.test())

There is am implied executor.sutdown() call, which waits for the submitted tasks to complete. See the documentation. Since you use this construct on the main thread, all GUI updates will be blocked until all the submitted tasks complete. So you should typically not use that construct on the main thread of a kivy app.

A second problem is that the creation and display of an MDDialog should be done on the main thread, so submitting a method like pop_up1() to the executor can be problematic.

A third issue is your attempt to reuse the MDDialog with the if not self.dialog: condition. You cannot reuse an MDDialog anyway.

So, taking all that into account, here is modified version of your code that does what I think you want:

from kivy.clock import Clock, mainthread
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivymd.app import MDApp
from kivymd.uix.dialog import MDDialog
import concurrent.futures

KV = '''
<Content>
    orientation: "vertical"
    spacing: -40
    
    MDSpinner:
        size_hint: None, None
        size: dp(46), dp(46)
        pos_hint: {'center_x': 0.1}
        active: True
    MDLabel:
        text: "Processing..."
        pos_hint: {'center_x': .7}

FloatLayout:

    MDFlatButton:
        text: "ALERT DIALOG"
        pos_hint: {'center_x': .5, 'center_y': .5}
        on_release: app.start()
'''


class Content(BoxLayout):
    pass

class Example(MDApp):
    dialog = None

    def build(self):
        return Builder.load_string(KV)

    def start(self):
        # this must be done on the main thread
        self.pop_up1()

        executor = concurrent.futures.ThreadPoolExecutor()
        # f1 = executor.submit(self.pop_up1)  # this must be done on the main thread
        f2 = executor.submit(self.test)


    def pop_up1(self):
        '''Displays a pop_up with a spinning wheel'''
        self.dialog = MDDialog(
            size_hint=(.45, None),
            auto_dismiss=True,
            type="custom",
            content_cls=Content(),
        )
        self.dialog.open()

    def test(self):
        '''Counts to 1000000 and then it closes pop_up1 and opens pop_up2'''
        for number in range(100000):
            print(number)
        self.dismiss()
        Clock.schedule_once( self.pop_up2)  # pop_up2() must be done on the main thread

    def pop_up2(self,*args):
        self.dialog = MDDialog(
            title="Done",
            size_hint=(.6, None),
            text="Done",
                )
        self.dialog.open()

    @mainthread
    def dismiss(self, *args):
        self.dialog.dismiss()


Example().run()