2015-09-04 17 views
0

簡要說明什麼我想要實現:多線程與matplotlib和wxPython的

我正在使用Python,wxPython中,和matplotlib建立了一個分析軟件。我試圖實現一個函數,程序可以在執行一些分析計算後繪製結果。目前,程序在執行計算時會凍結(並且計算時間長達10秒,具體取決於數據量),所以我嘗試使用線程創建非阻塞程序來改善用戶體驗。

問題我越來越

我不斷收到此錯誤: (PyAssertionError:C++斷言 「hdcDst & & hdcSrc」 未能在......的\ src \ MSW \ dc.cpp( 2559)在AlphaBlt():AlphaBlt():無效的HDC)

和谷歌搜索並沒有真正幫助找出原因。

我會發布帖子底部的完整回溯。

這裏是我的代碼:

import wx 
import time 
import matplotlib.pyplot as plt 

from wx.lib.pubsub import Publisher as pub 
from threading import Thread 

def plotgraph(x,y,sleeptime): 
    plt.plot(x,y) 
    #Simulate long process using time.sleep 
    time.sleep(sleep time) 
    #Send out a message once process is completed 
    pub.sendMessage('PLOT','empty') 

class listener(): 
    def __init__(self,name): 
     self.name = name 
     #Listens to message 
     pub.subscribe(self.Plot,'PLOT') 
     pass 

    def Plot(self,message): 
     print self.name 
     plt.show() 
     print 'printed' 


waiting = listener('Bob') 

t1 = Thread(target=plotgraph,args=([1,2,3],[1,2,3],5)) 
t1.start() 
t2 = Thread(target=plotgraph,args=([1,2,3],[1,2,3],3)) 
t2.start() 

基本上,用戶將被點擊的圖形用戶界面的圖標,將觸發功能,可實現由「plotgraph()」在這裏模擬的一些分析計算。目前,沒有使用線程,plotgraph()會阻止我的整個程序,所以我試圖使用線程來執行計算來釋放我的GUI。

但是,當我試圖在線程中繪製我的GUI時,即在plotgraph()中有plt.show()時,圖形會再次消失。當我點擊GUI上的按鈕來第二次產生線程時,我得到同樣的錯誤。

所以我試着通過在線程結束後發送消息來解決它,以便plt.show()會在線程外部發生,但我仍然得到相同的錯誤。

我似乎無法在網上找到類似的錯誤,除了2008年發佈的一條帖子。如果任何人都可以提供幫助,那將非常棒!

簡而言之 我需要一種方法來實現排序回調函數,讓我在一個線程中進行分析計算,那麼一旦計算完成,騰出我的GUI繪製圖表。如果有人能向我解釋這裏出了什麼問題,或者可以建議一種替代方法,那將會很棒。非常感謝!!

以下是完整回溯:

File "C:\Users\chaishen\AppData\Local\Enthought\Canopy32\App\appdata\canopy-1. 
.5.3123.win-x86\lib\threading.py", line 810, in __bootstrap_inner 
    self.run() 
File "C:\Users\chaishen\AppData\Local\Enthought\Canopy32\App\appdata\canopy-1. 
.5.3123.win-x86\lib\threading.py", line 763, in run 
    self.__target(*self.__args, **self.__kwargs) 
File "<ipython-input-5-0cb01f87e97a>", line 13, in plotgraph 
    pub.sendMessage('PLOT','empty') 
File "C:\Users\chaishen\AppData\Local\Enthought\Canopy32\User\lib\site-package 
\wx\lib\pubsub.py", line 811, in sendMessage 
    self.__topicTree.sendMessage(aTopic, message, onTopicNeverCreated) 
File "C:\Users\chaishen\AppData\Local\Enthought\Canopy32\User\lib\site-package 
\wx\lib\pubsub.py", line 498, in sendMessage 
    deliveryCount += node.sendMessage(message) 
File "C:\Users\chaishen\AppData\Local\Enthought\Canopy32\User\lib\site-package 
\wx\lib\pubsub.py", line 336, in sendMessage 
    listener(message) 
File "<ipython-input-5-0cb01f87e97a>", line 24, in Plot 
    plt.show() 
File "C:\Users\chaishen\AppData\Local\Enthought\Canopy32\User\lib\site-package 
\matplotlib\pyplot.py", line 155, in show 
    return _show(*args, **kw) 
File "C:\Users\chaishen\AppData\Local\Enthought\Canopy32\User\lib\site-package 
\matplotlib\backend_bases.py", line 154, in __call__ 
    manager.show() 
File "C:\Users\chaishen\AppData\Local\Enthought\Canopy32\User\lib\site-package 
\matplotlib\backends\backend_wx.py", line 1414, in show 
    self.canvas.draw() 
File "C:\Users\chaishen\AppData\Local\Enthought\Canopy32\User\lib\site-package 
\matplotlib\backends\backend_wxagg.py", line 50, in draw 
    self.gui_repaint(drawDC=drawDC) 
File "C:\Users\chaishen\AppData\Local\Enthought\Canopy32\User\lib\site-package 
\matplotlib\backends\backend_wx.py", line 911, in gui_repaint 
    drawDC.DrawBitmap(self.bitmap, 0, 0) 
File "C:\Users\chaishen\AppData\Local\Enthought\Canopy32\User\lib\site-package 
\wx\_gdi.py", line 3460, in DrawBitmap 
    return _gdi_.DC_DrawBitmap(*args, **kwargs) 
yAssertionError: C++ assertion "hdcDst && hdcSrc" failed at ..\..\src\msw\dc.cp 
(2559) in AlphaBlt(): AlphaBlt(): invalid HDC 
+0

我不能讓發佈訂閱工作,但我發現wx.lib。delayedresult更容易做類似的事情。 wxpython演示有一個很好的例子,另一個在這裏http://showmedo.com/videotutorials/video?name=8770000&fromSeriesID=877 – otterb

+0

@otterb非常感謝!我嘗試過使用startWorker,但是當'線程'死亡時,我的繪圖窗口會自動終止。 :( 你知道一個方法來規避嗎? – Shengy90

回答

0

我想你需要什麼wx.PyEventBinder。 它的工作原理是這樣的:

anEVT_CALCULATED = wx.NewEventType() 
EVT_CALCULATED = wx.PyEventBinder(anEVT_CALCULATED, 1) 

def onCalculate(self, event): # this is your click 
    calc_thread = CalculatorThread(self, params) 
    calc_thread.start() 
    return 

def onConnected(self, event): 
    ''' this is where your thread comes back ''' 
    self.doSomeThingLikePlotting(event.resultdata) 

class CalcEvent(wx.PyCommandEvent): 
    ''' Event to signal that the thread has calculated''' 
    def __init__(self, etype, eid, resultdata): 
     wx.PyCommandEvent.__init__(self, etype, eid) 
     self.resultdata = resultdata 

class CalculatorThread(threading.Thread): 
    ''' This is the thread doing your calculation and handing it back''' 
    def __init__(self, listener, params): 
     threading.Thread.__init__(self) 
     self.listener = listener 
     self.params = params 

    def run(self): 
     resultdata = calculate(params) # this is your calculation 
     event = CalcEvent(anEVT_CALCULATED, -1, resultdata=resultdata) 
     wx.PostEvent(self.listener, event) 
     return 

當然,你需要一個行添加到您__init__

self.Bind(EVT_CONNECTED, self.onCalculated)