Nec Xelos
Nec Xelos

Reputation: 409

How to Update Kivy Label and Progress Bar with data from current process?

I have a function that reads a gigantic JSON file and then saves the data to another JSON file (after some filtering and changing). My code looks like that:

        def my_method(self, source_file, result_file):
            with open (source_file, 'r', encoding="utf-8") as file:
                data = json.load(file)
            self.ids.my_progress_bar.max = len(data)
            with open(result_file, 'w') as file:
                for item in data:
                ### Some data filtering and changing here.
                    json.dump(item, file)
                ### Part of the code that doesn't work!
                    self.ids.my_progress_bar.value += 1
                    self.ids.my_label.text = item['item_name']
                ### And the rest works!
            del data

Problem is neither Label nor Progress Bar update.

From what I found in semi-similar topics across the web, it's most likely because calls to Kivy GUI resolve after the loop ends and are ignored during loop or something like that.

I have no idea how to make it work though. I'd prefer a solution that changes my current loop as little as possible (I provided simplified code, there's really lots of data processing there and I'm not ready to rewrite it from scratch) and are not performance-killers (what I have here is already pretty slow and resources-eating). Threading maybe? I never used threading before though so I'd need a very detailed/commented snippet to make it work.

Thanks in advance

Upvotes: 1

Views: 373

Answers (1)

John Anderson
John Anderson

Reputation: 38857

I haven't tested this (I don't have the rest of your code), but this should give you the idea of how to do it:

    def update_progress(self, text, dt):
        # stuff that must be done on the main thread
        self.ids.my_progress_bar.value += 1
        self.ids.my_label.text = text

    def my_method(self, source_file, result_file):
        with open (source_file, 'r', encoding="utf-8") as file:
            data = json.load(file)
        self.ids.my_progress_bar.max = len(data)
        with open(result_file, 'w') as file:
            for item in data:
            ### Some data filtering and changing here.
                json.dump(item, file)
            ### Part of the code that doesn't work!
                # schedule this for running on the main thread
                Clock.schedule_once(functools.partial(self.update_progress, item['item_name']))
            ### And the rest works!
        del data


    # and wherever `my_method` is called:
    threading.Thread(target=self.my_method, args=(source_file, result_file)).start()

The threading.Thread().start() starts your my_method in another thread. The Clock.schedule_once() calls the code that must be run on the main thread (self.update_progress). The functools.partial is used just to provide the correct arguments to the self.update_progress method.

Upvotes: 2

Related Questions