0

I'm writing a practice GUI application that helps manage Android apps by ADB.

But I've ran into an issue where the status bar won't update until the uninstall_package function, that is called from tk.Menu, has finished.

The first self.status_bar.text.set isn't shown, but the last one is. I've tested replacing the terminal function with time.wait() after the first self.status_bar.text.set, but that didn't work.

I came across this related issue, but it hasn't helped resolve it. https://stackoverflow.com/a/32504779/6318164

This is the script. I've minimised it to only include the main parts related to the issue.

class App(tk.Tk):
    def __init__(self):
        super().__init__()

        self.geometry('640x480')

        self.menu_bar = MenuBar(self)
        self.status_bar = StatusBar(self)
        self.tab = Tab(self)

    def uninstall_package(self):
        if self.tab.get_selected_name() == 'Third Party':
            # com.company.app
            package = self.tab.third_party.get_selected_items()[0]

            answer = messagebox.askyesno(
                title='Confirm',
                message='Uninstall package:\n{}'.format(package)
            )

            if not answer:
                return

            self.status_bar.text.set('Uninstalling {}...'.format(package))

            # function halts until the terminal process has finished
            process = terminal('adb uninstall {}'.format(package))

            if process.stdout:
                self.status_bar.text.set('Success')
            else:
                messagebox.showerror('An error occurred.')

            # other functions...

class MenuBar(tk.Menu):
    def __init__(self, master):
        super().__init__(master)

        action_menu = tk.Menu(self, tearoff=0)
        action_menu.add_command(label='Uninstall Selected Package', command=master.uninstall_package)

        self.add_cascade(label='Action', menu=action_menu)

        master.config(menu=self)

class StatusBar(tk.Frame):
    def __init__(self, master):
        super().__init__(master)

        self.text = tk.StringVar()
        self.text.set('Ready')

        label = tk.Label(self, anchor='w', bd=1, relief=tk.SUNKEN, textvariable=self.text)
        label.pack(fill='x')

        self.pack(side='bottom', fill='x')
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Nova
  • 2,000
  • 3
  • 14
  • 24
  • 1
    You probably want to either use `subprocess.Popen` and stream data from there or use another thread. You can't run blocking code in the same thread as the `.mainloop` because it will block it and `tkinter` won't be able to update. You need a combination of `.after` and a thread or `Popen` (or both?) – Matiiss Oct 18 '21 at 22:40

1 Answers1

1

Try this just after setting the status bar text:

tk.update_idletasks()
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Maddy
  • 59
  • 1