2013-01-24 29 views
3

我需要在我的PyQt应用程序中显示一些图表,所以我写下了这些代码。 这是作品,但有时画图会花费很多时间,它会“冻结”主窗口。如何在PyQt的另一个线程中运行Matplotlib

我觉得在另一个线程中应该解决它。但我该怎么做呢? 或者,还有另一种在“非块”模式下绘制图表的方法?

from PyQt4 import QtGui 
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas 
from matplotlib.figure import Figure 

class MplCanvas(FigureCanvas): 

    def __init__(self): 
     self.fig = Figure() 
     self.axes = self.fig.add_subplot(111) 

     # do something... 
     FigureCanvas.__init__(self, self.fig) 
     FigureCanvas.setSizePolicy(self, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) 
     FigureCanvas.updateGeometry(self) 
     # do something... 

    def draw(self): 
     # do something... 
+0

现在实施类似的。这是我的想法。你必须使用多个类,一个是基于PyQt的QDialog或类似的GUI输出。另一个是基于QThread的工人类。一旦QThread完成绘图,它将使用PyQt信号引擎将图形和画布实例传递给GUI对象。我尝试将QDialog和QThread组合到一个类中,但显然你不能这样做。 (我相信你可以做到,但使用2个独立的类更容易) – Barmaley

回答

1

像这样简单用法的Python线程基础很容易。

你需要

import threading 

,然后,而不是仅仅调用x.draw(),创建一个线程,并按如下运行:

draw_thread = threading.Thread(target=x.draw) 
draw_thread.start() 

这可能会得到你至少90%的方式。您可以阅读文档以检测仍在运行的线程,等待线程等等。但内心而言,这并不难,如果只是简单的交互式图形,这可能就足够了。

但请注意,如果draw()引用全局变量,则可能出现竞态条件,从而导致程序不可靠。这是编写具有良好耦合,干净的接口和没有引用可变全局变量(除非使用锁来保护这些资源)的代码的另一个优点。

+0

你必须在PyQt中使用QThreads。简单的老线程无法正常工作 – Barmaley

+0

啊,给我的消息 - 感谢评论。 'QThreads'和'threading'线程配合好吗? – holdenweb

2

你应该我们QThreadsQt应用程序(使框架工作做所有的辛勤工作的你)

  1. 把你的时间在一个工人阶级费力的工作(即从QObject派生)

  2. 在你的类是caling的绘制中加入类似

    self.thread = QtCore.QThread(parent=self) 
    
    self.worker = Worker(parent=None) 
    self.worker.moveToThread(self.thread) 
    self.thread.start() 
    

并通过信号/插槽与您的工作人员进行通信。如果直接调用它(如self.worker.do_slow_stuff()),它将在您调用它的线程上运行,这将阻止主要事件循环使界面冻结。

一个好的explanation如何(以及not to)确实与QThread线程(读both..the第一个现在描述的默认行为)

+0

只是出于好奇而提出的一个问题。你有没有成功地让QThread应用程序工作,并在Windows上长时间保持稳定而没有崩溃?这让我疯狂,最终我放弃了,并改变了我的整个程序模型以使用多处理。 –

+0

从未在Windows上尝试过 – tacaswell

相关问题