2017-07-06 93 views
0

我想使用wxpython實時顯示隨機行走的軌跡。然而,面板在結束時只更新一次,顯示整個隨機遊走,而不是逐步更新並顯示時間過程。使用wxpython實時繪製數據流軌跡

我的第一個想法是使用wx.ClientDC()。DrawPoint(),但結果如上所述,我沒有看到單點繪製,但只顯示最終結果。

因此,我考慮使用wx.MemoryDC繪製存儲在內存中的位圖的軌跡,然後使用wx.ClientDC.DrawBitmap()以設置的時間間隔將緩衝的圖像複製到屏幕,以防翻轉圖像是瓶頸。結果仍然是一樣的,所以我希望你的幫助。

本練習的目的是用來自眼動儀的位置數據替換隨機行走,幀速率爲1000Hz,我希望能夠儘可能接近實時地觀察軌跡(顯示器的幀頻爲120Hz)。

這是我的代碼(大部分來自here):

import wx 
import random 
import time 
from time import asctime 

#------------------------------------------------------------------- 

def jmtime(): 
    return '[' + asctime()[11:19] + '] ' 

#------------------------------------------------------------------- 
class MyDrawingArea(wx.Window): 

    def __init__(self, parent, id): 
     sty = wx.NO_BORDER 
     wx.Window.__init__(self, parent, id, style=sty) 
     self.parent = parent 
     self.SetBackgroundColour(wx.WHITE) 
     self.SetCursor(wx.CROSS_CURSOR) 

     # Some initalisation, just to reminds the user that a variable 
     # called self.BufferBmp exists. See self.OnSize(). 
     self.BufferBmp = None 

     wx.EVT_SIZE(self, self.OnSize) 
     wx.EVT_PAINT(self, self.OnPaint) 
     wx.EVT_LEFT_DOWN(self,self.OnClick) 

    def OnSize(self, event): 
     print jmtime() + 'OnSize in MyDrawingArea' 
     # Get the size of the drawing area in pixels. 
     self.wi, self.he = self.GetSizeTuple() 
     # Create BufferBmp and set the same size as the drawing area. 
     self.BufferBmp = wx.EmptyBitmap(self.wi, self.he) 
     memdc = wx.MemoryDC() 
     memdc.SelectObject(self.BufferBmp) 
     # Drawing job 
     ret = self.DoSomeDrawing(memdc) 
     if not ret: #error 
      self.BufferBmp = None 
      wx.MessageBox('Error in drawing', 'CommentedDrawing', wx.OK | wx.ICON_EXCLAMATION) 


    def OnPaint(self, event): 
     print jmtime() + 'OnPaint in MyDrawingArea' 
     dc = wx.PaintDC(self) 
     dc.BeginDrawing() 
     if self.BufferBmp != None: 
      print jmtime() + '...drawing' 
      dc.DrawBitmap(self.BufferBmp, 0, 0, True) 
     else: 
      print jmtime() + '...nothing to draw' 
     dc.EndDrawing() 



    def OnClick(self,event): 
     pos = event.GetPosition() 
     dc = wx.ClientDC(self) 
     dc.SetPen(wx.Pen(wx.BLACK,1,wx.SOLID)) 

     dcwi, dche = dc.GetSizeTuple() 
     x = pos.x 
     y = pos.y 
     time_start = time.time() 

     memdc = wx.MemoryDC() 
     memdc.SelectObject(self.BufferBmp) 
     memdc.SetPen(wx.Pen(wx.BLACK,1,wx.SOLID)) 
     count = 1 
     runtime = 5 
     while (time.time() - time_start) < runtime: 
      x,y = random_walk(x,y,dcwi,dche) 
      memdc.DrawPoint(x,y) 
      if (time.time() - time_start) > count * runtime * 0.1: 
       print jmtime() + 'Random walk in MyDrawingArea' 
       count += 1 
       dc.BeginDrawing() 
       dc.DrawBitmap(self.BufferBmp, 0, 0, True) 
       dc.EndDrawing() 
     dc.BeginDrawing()   
     dc.DrawBitmap(self.BufferBmp, 0, 0, True) 
     dc.EndDrawing() 

    # End of def OnClick 

    def DoSomeDrawing(self, dc): 
     try: 
      print jmtime() + 'DoSomeDrawing in MyDrawingArea' 

      dc.BeginDrawing() 

      #~ raise OverflowError #for test 

      # Clear everything 
      dc.SetBrush(wx.Brush(wx.WHITE, wx.SOLID)) 
      dc.Clear() 

      dc.EndDrawing() 
      return True 

     except: 
      return False 

#------------------------------------------------------------------- 

class MyPanel(wx.Panel): 

    def __init__(self, parent, id): 
     wx.Panel.__init__(self, parent, id, wx.DefaultPosition, wx.DefaultSize) 

     self.drawingarea = MyDrawingArea(self, -1) 

     self.SetAutoLayout(True) 

     gap = 30 #in pixels 
     lc = wx.LayoutConstraints() 
     lc.top.SameAs(self, wx.Top, gap) 
     lc.left.SameAs(self, wx.Left, gap) 
     lc.right.SameAs(self, wx.Width, gap) 
     lc.bottom.SameAs(self, wx.Bottom, gap) 
     self.drawingarea.SetConstraints(lc) 

#------------------------------------------------------------------- 

# Usual frame. Can be resized, maximized and minimized. 
# The frame contains one panel. 
class MyFrame(wx.Frame): 

    def __init__(self, parent, id): 
     wx.Frame.__init__(self, parent, id, 'CommentedDrawing', wx.Point(0, 0), wx.Size(500, 400)) 
     self.panel = MyPanel(self, -1) 

     wx.EVT_CLOSE(self, self.OnCloseWindow) 

    def OnCloseWindow(self, event): 
     print jmtime() + 'OnCloseWindow in MyFrame' 
     self.Destroy() 

#------------------------------------------------------------------- 

class MyApp(wx.App): 

    def OnInit(self): 
     frame = MyFrame(None, -1) 
     frame.Show(True) 
     self.SetTopWindow(frame) 
     return True 

#------------------------------------------------------------------- 

def random_walk(x,y,sizex = 250, sizey = 200): 

    rn = random.randrange(0,2) 
    x_new = x + (1-rn) - rn 
    while x_new < 0 or x_new > sizex: 
     rn = random.randrange(0,2) 
     x_new = x + (1-rn) - rn 

    rn = random.randrange(0,2) 
    y_new = y + (1-rn) - rn 
    while y_new < 0 or y_new > sizex: 
     rn = random.randrange(0,2) 
     y_new = y + (1-rn) - rn 

    return x_new, y_new 

# end of def random_walk 

#------------------------------------------------------------------- 

def main(): 
    print 'main is running...' 
    app = MyApp(0) 
    app.MainLoop() 

#------------------------------------------------------------------- 

if __name__ == "__main__" : 
    main() 

#eof------------------------------------------------------------------- 

回答

0

這是我想出了一個解決方案。我使用Update()和Refresh()來觸發繪畫事件,而不是使用dc.DrawBitmap()將緩衝圖像複製到屏幕上。但是,我仍然不明白的是爲什麼我不能使用DrawBitmap()來完成相同的操作。

唯一的區別是OnPaint()使用PaintDC()和OnClick()我使用ClientDC()。

不管怎麼說,這是我的電流的OnClick()代碼:

def OnClick(self,event): 
    pos = event.GetPosition() 
    x = pos.x 
    y = pos.y 
    time_start = time.time() 

    memdc = wx.MemoryDC() 
    memdc.SelectObject(self.BufferBmp) 
    dcwi, dche = memdc.GetSizeTuple() 
    memdc.SetPen(wx.Pen(wx.BLACK,1,wx.SOLID)) 
    runtime = 10 
    while (time.time() - time_start) < runtime: 
     x,y = random_walk(x,y,dcwi,dche) 
     memdc.SelectObject(self.BufferBmp) 
     memdc.DrawPoint(x,y) 
     memdc.SelectObject(wx.NullBitmap) 
     self.Update() 
     self.Refresh() 
    print jmtime() + 'Random walk in MyDrawingArea done'