1

I have a relatively large application written in Python and using PyQT as a GUI frontend. The entire application is in one class, in one file.

Here's an example code:

class Application(QMainWindow):
  def __init__(self):
    super(etc...)

    self.connect(self.mainBtn, SIGNAL("clicked()"), self.do_stuff)

  def do_stuff(self):
    <checking some parameters>
    else:
      do_some_other_long_stuff()


  def do_some_other_long_stuff(self):
     500 lines of code of stuff doing

However, this is the problem: when I click the mainBtn, everything goes fine, except the GUI kind of freezes - I can't do anything else until the function is performed (and it's a web scraper so it takes quite a bit of time). When the function do_some_other_long_stuff ends, everything goes back to normal. This is really irritating.

Is there a way to somehow "background" the do_some_other_stuff process? I looked into QThreads and it seems it does just that, however that would require me to rewrite basically all of code, put half of my program in a different class, and therefore have to change all the variable names (when getting a variable from GUI class and putting it in working class)

Bo Milanovich
  • 7,995
  • 9
  • 44
  • 61

1 Answers1

2

Duplicate of Handling gui with different threads, How to keep track of thread progress in Python without freezing the PyQt GUI?, etc.

Your do_stuff() function needs to start up the computing thread and then return. Multi-threading is the name given to running multiple activities in a single process - by definition if something is going on "in the background", it's running on a separate thread. But you don't need to split functions into a different classes to use threads, just be sure that the computing functions don't do anything with the GUI and the main thread doesn't call any of the functions used by the computing thread.

EDIT 10/23: Here's a silly example of running threads in a single class - nothing in the language or the threading library requires a different class for each thread. The examples probably use a separate class for processing to illustrate good modular programming.

from tkinter import *
import threading

class MyApp:
    def __init__(self, root):
        self.root = root
        self.timer_evt = threading.Event()
        cf = Frame(root, borderwidth=1, relief="raised")
        cf.pack()
        Button(cf, text="Run", command=self.Run).pack(fill=X)
        Button(cf, text="Pause", command=self.Pause).pack(fill=X)
        Button(cf, text="Kill", command=self.Kill).pack(fill=X)

    def process_stuff(self):        # processing threads
        while self.go:
            print("Spam... ")
            self.timer_evt.wait()
            self.timer_evt.clear()

    def Run(self):                  # start another thread
        self.go = 1
        threading.Thread(target=self.process_stuff, name="_proc").start()
        self.root.after(0, self.tick)

    def Pause(self):
        self.go = 0

    def Kill(self):                 # wake threads up so they can die
        self.go = 0
        self.timer_evt.set()

    def tick(self):
        if self.go:
            self.timer_evt.set()    # unblock processing threads
            self.root.after(1000, self.tick)

def main():
    root = Tk()
    root.title("ProcessingThread")
    app = MyApp(root)
    root.mainloop()

main()
Community
  • 1
  • 1
Dave
  • 3,834
  • 2
  • 29
  • 44
  • thanks. So how would one use multiple threads without creating a different Class()? All the examples that I've found online use different classes. – Bo Milanovich Oct 22 '11 at 01:49
  • 1
    @Deusdies: With 500 lines or more in a single class, wouldn't you in fact want to refactor this huge "[god-class](http://en.wikipedia.org/wiki/God_object)"? – Hovercraft Full Of Eels Oct 22 '11 at 02:06
  • @HovercraftFullOfEels: that is the ultimate solution. But I'd rather not to have to do that, if possible. – Bo Milanovich Oct 22 '11 at 02:23