C.Gibbons
C.Gibbons

Reputation: 323

How to get a loading gif to work while running a command

I am trying to get a gif of a loading circle to play while I run another python script.

When I click a button I get a popup that has a loading gif, in the background I want to run a python script while this gif loads. Once the script is complete the popup closes.

So far all of this works except the gif freezes once the other python script starts running.

I have tried using os.system(), subprocess.run() and the controversial subprocess.Popen(). I have also tried using the threading and multiprocessing python modules.

Threading seems to be the way to go however I still get the same result (the gif freezing once I start running the other python script).

I am aware that there are many other similar questions out there, however I can assure you I have read them all and tried their solutions, but for some reason they are not working for me. I have been working on this for days and cannot find a solution so any help would be greatly appreciated.

For an overall picture, I am writing a python3.7 application using kivy to create a GUI. I am running this application on a Raspberry Pi 4.

The following is are snippets of my current, relevant code: (The "..." indicate where other irrelevant code is)

main.py

class SetttingsWindow(Screen):
    def __init__(self, **kwargs):
        super(SettingsWindow, self).__init__(**kwargs)
        Clock.schedule_interval(self.check, 1)

    def check(self, dt):
        global wset
        if wset:
            self.start_thread()
        else:
            pass

    def start_thread(self):
        t = threading.Thread(target=self.connect)
        t.start()
        time.sleep(1)
        t.join()

    def connect(self):
        global wset
        os.system('sudo python /home/pi/app/connect.py')
        wset = False
        loadingPopup.dissmiss()

    def set(self):
        Popup.open()


class PopUp(FloatLayout):
    def __init__(self, **kwargs):
        super(PopUp, self).__init__(**kwargs)

    def change(self):
        global wset
        if ... :
            PopUp.dismiss()
        else:
            ...
            PopUp.dissmiss()
            wset = True

    def setLoad(self):
        loadingPopup.open()


class LoadingPopUp(FloatLayout):
    pass

main.kv

<SettingsWindow>
    ...
    Button:
        text: "Setup"
        on_release:
            root.set()
    ...
...
<PopUp>
    ...
    Button:
        text: "Set"
        on_release:
            root.change()
            root.setLoad()
    ...
...
<LoadingPopUp>
    Image:
        source: "loading.gif"
        anim_delay: 0.05
        keep_data: True

Upvotes: 2

Views: 883

Answers (1)

John Anderson
John Anderson

Reputation: 39072

Your check() method will be run in the main thread (as called by Clock.schedule_interval). That method calls start_thread, which starts a new thread to run your connect method. All that is fine, but then you call t.join(), which stops the main thread until your connect method completes. While waiting for the connect thread to complete, your GUI will stop completely. I suggest removing the lines:

    time.sleep(1)
    t.join()

to allow the GUI to operate.

Upvotes: 1

Related Questions