Which GUI frameworks are best for a multi-threaded Python program?
I am writing a multi-threaded Python program with a GUI, with several modules that "touch" the GUI by changing text and background colors. I am currently using PyGTK and am finding that the GUI sometimes开发者_运维知识库 crashes "silently" (no error messages; the program just terminates), and sometimes encounters segmentation faults.
This site notes that GTK is not completely thread-safe, and that PyGTK multi-threaded programming is tricky. Are there better Python GUI frameworks for multi-threaded programs that are less likely to produce problems?
Ohh, I definitely recommend PyQt4. At first, I didn't get all this SIGNAL
and EMIT
nonsense, but now that I've made a program with it, the QThread
module is amazingly useful.
As for stability, I have never had a crash, ever. Even while I was debugging half-functional code, QT didn't have any problems. It just threw an error to the console window whenever I clicked a button with an invalid signal slot.
GTK, on the other hand, just 'sploded once in a while with no errors whatsoever. Just your extremely descriptive and friendly Segmentation Fault
. That was one of the reasons I find PyQt a joy to work with. When you get an error, you actually know what's wrong.
I'm pretty sure it's personal preference after that, but one more plus is native-looking GUIs on Mac, Linux, and Windows. GTK+ on Windows (don't get me wrong. I use Ubuntu) just has this X-org feel to it, which disturbs me.
Good luck!
Just to make PyQt a bit more attractive, here's an excerpt from my book binding application (it's a bit messy):
class Binder(QtCore.QThread):
'''
Class for binding the actual book
'''
def __init__(self, parent = None):
super(Binder, self).__init__(parent)
def initialize(self, pages, options, outfile):
self.pages = pages
self.options = options
self.outFile = outfile
self.book = organizer.Book()
self.enc = Encoder(self.options)
self.ocr = ocr.OCR(self.options)
self.connect(self.enc, QtCore.SIGNAL('updateProgress(int, int)'), self.updateProgress)
def updateProgress(self, percent, item):
self.emit(QtCore.SIGNAL('updateProgress(int, QString)'), int(percent), 'Binding the book...')
self.emit(QtCore.SIGNAL('updateBackground(int, QColor)'), int(item), QtGui.QColor(170, 255, 170, 120))
if int(percent) == 100:
time.sleep(0.5)
self.emit(QtCore.SIGNAL('finishedBinding'))
def run(self):
self.die = False
for page in self.pages:
self.add_file(page, 'page')
if not self.die:
self.analyze()
if not self.die:
self.book.get_dpi()
if self.options['ocr'] and not self.die:
self.get_ocr()
if not self.die:
self.enc.initialize(self.book, self.outFile)
self.enc.start()
If you are updating the GUI from a thread, you might want to use gobject.idle_add()
so that the GUI update function is called later in the loop, most GUI frameworks (like Qt) require you to add a callback that will be called later when the mainloop is idle. GTK also supports calling the GUI functions from threads by using the gtk.gdk.lock
context manager or calling gtk.gdk.threads_enter
and gtk.gdk.threads_leave
around your GUI calls.
So you either do:
gobject.idle_add(lambda: window.whatever(arg1, arg2))
Or you do:
with gtk.gdk.lock:
window.whatever(arg1, arg2)
精彩评论