2017-07-06 6 views
0

Je veux utiliser wxpython pour montrer la trajectoire d'une marche aléatoire en temps réel. Cependant, le panneau n'est mis à jour qu'une seule fois à la fin, montrant l'ensemble de la marche aléatoire au lieu de la mettre à jour pas à pas et de montrer l'évolution dans le temps. La première idée consistait à utiliser wx.ClientDC(). DrawPoint() mais le résultat était comme décrit ci-dessus où je ne voyais pas de points uniques dessinés mais seul le résultat final était affiché. Donc à la place, j'ai pensé à utiliser wx.MemoryDC pour dessiner la trajectoire vers un bitmap stocké en mémoire, puis utiliser wx.ClientDC.DrawBitmap() pour copier l'image tamponnée à l'écran à des intervalles de temps définis au cas où l'image serait retournée était le goulot d'étranglement. Le résultat est toujours le même et j'espère que vous m'aiderez. Le but de cet exercice est de remplacer la marche aléatoire par des données de position provenant d'un eye tracker avec une fréquence d'images de 1000 Hz et j'aimerais pouvoir visualiser la trajectoire le plus près possible en temps réel (La fréquence d'image du moniteur est de 120 Hz).Dessiner une trajectoire à partir d'un flux de données en temps réel en utilisant wxpython

Ceci est mon code (la majeure partie provient de 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------------------------------------------------------------------- 

Répondre

0

C'est la solution que je suis venu avec. Au lieu d'utiliser dc.DrawBitmap() pour copier l'image mise en mémoire tampon sur l'écran, j'ai utilisé Update() et Refresh() pour déclencher un événement paint. Cependant, ce que je ne comprends toujours pas, c'est pourquoi je ne peux pas utiliser DrawBitmap() pour accomplir la même chose. La seule différence est que OnPaint() utilise PaintDC() et dans OnClick() j'utilise ClientDC().

Quoi qu'il en soit, voici mon code actuel pour 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'