多线程Python程序最适合哪些GUI框架?

5 投票
2 回答
4675 浏览
提问于 2025-04-16 10:48

我正在写一个多线程的Python程序,这个程序有一个图形用户界面(GUI),里面有几个模块会通过改变文本和背景颜色来“触碰”这个界面。目前我在使用PyGTK,但我发现这个界面有时候会“悄悄地”崩溃(没有错误信息,程序就直接结束了),有时候还会出现段错误。

这个网站提到GTK并不是完全线程安全的,使用PyGTK进行多线程编程是比较棘手的。有没有更好的Python GUI框架,适合多线程程序,能减少出现问题的可能性呢?

2 个回答

0

如果你想从一个线程更新图形界面(GUI),你可能需要用到 gobject.idle_add() 这个方法,这样可以让更新界面的函数在主循环稍后被调用。大多数图形界面框架(比如Qt)都要求你添加一个回调函数,这个函数会在主循环空闲的时候被调用。GTK也支持从线程中调用图形界面函数,你可以使用 gtk.gdk.lock 这个上下文管理器,或者在你的图形界面调用前后使用 gtk.gdk.threads_entergtk.gdk.threads_leave

所以你可以选择这样做:

gobject.idle_add(lambda: window.whatever(arg1, arg2))

或者你可以这样做:

with gtk.gdk.lock:
    window.whatever(arg1, arg2)
4

哦,我绝对推荐 PyQt4。刚开始的时候,我对那些 SIGNALEMIT 的东西搞不太懂,但现在我用它做了一个程序,发现 QThread 模块真的是非常有用。

至于稳定性,我从来没有遇到过崩溃。即使在调试那些半成品的代码时,QT也没有出现任何问题。每当我点击一个信号槽不正确的按钮时,它只是把错误信息抛到控制台窗口。

而GTK有时候就会突然崩溃,完全没有任何错误提示。就只会出现一个非常不友好的 Segmentation Fault。这也是我觉得使用PyQt很愉快的原因之一。当你遇到错误时,你实际上知道哪里出问题了。

之后我觉得这主要是个人喜好,但还有一个优点就是在Mac、Linux和Windows上看起来都很原生的界面。GTK+在Windows上(别误会,我用的是Ubuntu)总给我一种X-org的感觉,这让我觉得不太舒服。

祝你好运!


为了让PyQt看起来更吸引人,这里有我书籍绑定应用程序的一小段代码(有点乱):

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()

撰写回答