0

When I run the app, the run button is still responsive for a few seconds before the entire app freezes but the thread continues running. Where is the problem in my code and how do fix it?

import threading
from tkinter import *
from tkinter import ttk


class SubExtractor:
    def __init__(self, root):
        self.root = root
        self._create_layout()

    def _create_layout(self):
        self.root.title("Sub Extractor")

        self._menu_bar()

        self.main_frame = ttk.Frame(self.root, padding=(5, 5, 5, 15))

        self._video_frame()
        self._progress_frame()
        self._output_frame()

        self.main_frame.grid()

    def _menu_bar(self):
        self.root.option_add('*tearOff', FALSE)

        menubar = Menu(self.root)
        self.root.config(menu=menubar)

        menu_file = Menu(menubar)
        menu_settings = Menu(menubar)

        menubar.add_cascade(menu=menu_file, label="File")
        menubar.add_cascade(menu=menu_settings, label="Settings")

        menu_file.add_command(label="Open", command=self._open_file)
        menu_file.add_command(label="Close", command=self._close_window)

        menu_settings.add_command(label="Language", command=self._language_settings)
        menu_settings.add_command(label="Extraction", command=self._extraction_settings)

    def _video_frame(self):
        video_frame = ttk.Frame(self.main_frame, borderwidth=2, relief="ridge", width=1000, height=600)
        video_frame.grid()

    def _progress_frame(self):
        progress_frame = ttk.Frame(self.main_frame)
        progress_frame.grid(row=1, sticky="W")

        self.run_button = ttk.Button(progress_frame, text="Run", command=self._run)
        self.run_button.grid(pady=10, padx=30)

        self.progress_bar = ttk.Progressbar(progress_frame, orient=HORIZONTAL, length=800, mode='determinate')
        self.progress_bar.grid(column=2, row=0)

    def _output_frame(self):
        output_frame = ttk.Frame(self.main_frame)
        output_frame.grid(row=2)

        self.text_output_widget = Text(output_frame, width=97, height=12, state="disabled")
        self.text_output_widget.grid()

        output_scroll = ttk.Scrollbar(output_frame, orient=VERTICAL, command=self.text_output_widget.yview)
        output_scroll.grid(column=1, row=0, sticky="N,S")

        self.text_output_widget.configure(yscrollcommand=output_scroll.set)

    def _close_window(self):
        self._stop_run()
        self.root.quit()

    def _stop_run(self):
        self.interrupt = True
        self.run_button.configure(text="Run", command=self._run)

    def _text_to_output(self, text):
        self.text_output_widget.configure(state="normal")
        self.text_output_widget.insert("end", f"{text}\n")
        self.text_output_widget.see("end")
        self.text_output_widget.configure(state="disabled")

    def long_running_method(self):
        num = 100000
        self.progress_bar.configure(maximum=num)
        for i in range(0, num):
            if self.interrupt:
                break
            self._text_to_output(f"Line {i} of {num}")
            self.progress_bar['value'] += 1
        self._stop_run()

    def _run(self):
        self.interrupt = False
        self.run_button.configure(text='Stop', command=self._stop_run)
        threading.Thread(target=self.long_running_method).start()


rt = Tk()
SubtitleExtractorGUI(rt)
rt.mainloop()

What I expect to accomplish is for the loop to insert texts in the text widget while I can still freely move and use other buttons on the app.

  • You can understand more on Python multi-threading on this [question](https://stackoverflow.com/questions/20939299/does-python-support-multithreading-can-it-speed-up-execution-time). The for loop inside `long_running_method()` may be a bit high CPU usage. It is better to call `time.sleep(0.01)` after `self.progress_bar['value'] += 1` so to let other threads to run (switching threads). – acw1668 Dec 29 '22 at 01:56
  • @acw1668 Thanks for the reply. Is there any alternative if I want the loop inside to be fast? – Victor N Dec 29 '22 at 04:21
  • You can sleep shorter, like `time.sleep(0.0001)`. But I think that the for loop is just a simulation, the real task may not be such high CPU usage. – acw1668 Dec 29 '22 at 05:08
  • Typo error: Should be rt = Tk() app = SubExtractor(rt) rt.mainloop() – toyota Supra Feb 27 '23 at 21:50

0 Answers0