views:

78

answers:

1

I am trying to get a PyQT GUI running ontop of my python application and I have tried to get it separated into 2 threads so the GUI would be responsive while my main running loop goes, but I have not been able to get it going. Maybe I am misunderstanding it. Here is what I've tried:

My Window and Worker thread are defined as follows:

class Window(QWidget):
    def __init__(self, parent = None):
        QWidget.__init__(self, parent)
        self.thread = Worker()

        start = QPushButton("Start", self)
        QObject.connect(start, SIGNAL("clicked()"), MAIN_WORLD.begin)

        hbox = QVBoxLayout(self)
        hbox.addStretch(4)

class Worker(QThread):
    def __init__(self, parent = None):
        QThread.__init__(self, parent)

if __name__ == '__main__':
    MAIN_WORLD = World()
    app = QApplication(sys.argv)
    window = Window()
    window.show()
    sys.exit(app.exec_())

which seems to follow very closely to online examples. My World class is running a loop that is infinite once the user clicks "Start" until it's clicked again. Here is part of the definition of it.

class World(QThread):
    def __init__(self, parent = None):
        QThread.__init__(self, parent)
        self.currentlyRunning = False
        //snip

    def begin(self):
        if self.currentlyRunning:
            self.currentlyRunning = False
        else:
            self.currentlyRunning = True
            self.MethodThatDoesUsefulStuff()

edit: I have noticed that I'm not really "using" my worker thread. How do I create my world thread as a worker thread?

+1  A: 

After looking more closely at your code, you have MAIN_WORLD started before QApplication, which isn't what you want.

You want to do something like this:

if __name__ == '__main__':
    app = QApplication(sys.argv)
    sys.exit(app.exec_())

And, in your Window class:

class Window(QWidget):
    def __init__(self, *args):
        self.world_thread = World();
        # ...

The above will allow the main thread to control the gui and allow the worker threads to work in the background.

Kaleb Pederson
In this case, how do you keep your GUI consistently responsive while other code runs? Strange..
Mark
I edited the post to briefly describe consequences of your design. Can you elaborate on what your thread is doing?
Kaleb Pederson
I'm not familiar with the producer/consumer problem, but it doesn't seem that way. The infinite loop is running generations of a GA indefinitely until the GUI stops it.
Mark
Yeah, that's very different than the producer/consumer problem. I'll have to defer to somebody else. You might be able to call `QApplication.processEvents()` within your infinite loop, but I'm not sure that will work within threads (and it's really an ugly hack rather than an appropriate fix).
Kaleb Pederson
This is wrong. The GIL is released every 100 Python ticks, no matter if it's in a infinity loop. I suggest watching the video you linked to in your answer. http://blip.tv/file/2232410
Georg
Although that is a hack, it worked, hahah.
Mark
@Mark: *Either* use threads *or* use `QApplication.processEvents()`. Both can solve your problem, one of them is more advanced, but both together doesn't make any sense.
Georg
@Georg - Thanks for the info. Watching the full video now. Do you know how the GIL is then assigned to other threads? It certainly doesn't appear that the other threads are getting a hold of the GIL, otherwise the main gui thread should be doing updates?
Kaleb Pederson
@Kaleb: The thread handling is given back to the OS, which decides which thread to run. I bet his infinity loop is running in the main thread instead of in the worker threads.
Georg
@Georg - you're right again! Less the missing code, it looks like it's doing exactly that.
Kaleb Pederson