本文程序在Windows7 + python2.7 + wx2.9 + pygame1.9 下调试正常通过。
这几天在给一座桥写实时监控程序(众:你丫去年不就在写这玩意儿么,怎么今年又写开了……答:去年写的是个检测,就相当于给数据做了个皮肤,今年做的是监测,连着几百号传感器呢,技术含量不能同日而语……)。出于种种目的我终于说服项目组允许我拿python写这个程序,以前就很少写GUI程序,这下自己也纯属赶鸭子上架,结果没想到还遇到了个麻烦。 是这样的,桥上有个传感器,可以感应到有车辆从桥上经过,这个传感器可以记录到这个车的车速、加速度、轴重、轴距等等信息,然后工控机1受到这些数据后会向局域网广播,我写的程序跑在工控机2上,收到数据在屏幕显示就行了,这个过程倒是不难,只要下面几句就能完成:

  1. s=socket.socket(socket.af_inet,socket.sock_dgram)   
  2. s.setsockopt(socket.sol_socket,socket.so_reuseaddr,1)   
  3. socket.setdefaulttimeout(0.5)   
  4. ip=socket.gethostbyname(socket.gethostname())   
  5. d,a=s.recvfrom(90)   
  6. s.close()  

 

因为这个数据什么时候发过来并不知道,所以应该开个线程然后while循环这句d,a=s.recvfrom(90),当收到数据就出发个事件,但是我研究好久线程间通信、事件什么的也没弄出来,只好写了个轮循,就是收到数据就放到一个大家都能访问的空列表里,在画动画的时候不断检查这个列表长度,一旦列表长度大于0就从里边取数据,取一个删一个。这样写好像比较笨,再看了“小明明s à domicile”里写的设计模式后发现这个其实符合观察者模式,与其不断查这个列表不如在收数据这里调用画动画的函数,这样来通知效果应该会好些。说起来,在Python Essential Reference里有个生产者消费者模型,记得以前看操作系统原理看过,可惜没用上。 收上数据直接显示应该就行了吧,这个本来挺简单但是项目组要求这个显示一定要用个动画来显示,具体就是来个车要能看到一个格子里面有这个车的所有信息,然后这个格子要从屏幕下方移动到屏幕上方,定住;下一个移动到这个之后,如此循环,当屏幕上攒够4个就把最上面那个移走,整体往上顶一个,再把新的移上来,大致就是怎么个效果:

Record

Record

当然这个录的帧率偏低,不那么好看。实际动作还是蛮流畅的。 但是这个东西用python怎么做呢?如果用C#做的话,WPF里的动画能力很强,可以直接弄,Qt的话好像也有动画模块,至于wx……我就不说了。所以研究了半天我觉得还是用pygame来实现这个效果好了,网上查了下似乎wx和pygame合作也不错,就拿pygame来写了。 数据接受就是之前写的方式,接受上信息呢?研究了两天pygame,主要是研究这个教程,发现最好是继承sprint写个类,然后给他做那些动作,但是看了一上午sprint也没弄明白该怎么写,最后用最笨最简单的方法实现了。首先把显示的字弄好,做成surface,因为pygame不能换行,所以只好一行做一个,然后在显示这些字之前先把背景贴上去,然后在做动画的时候,先移动格子背景,绘制,在移动字,绘制,到了位置停下来,就这样。 但是还有个麻烦事,就是管理这么多车子,每次要看这个移到这儿,然后算下一个要移到哪,等凑够4个大家一起向上移怎么怎么……太麻烦了,有没有个好的数据结构帮我做这些管理呢?答案很简单,队列。我们设置一个长度为5的队列(用列表实现),接受的数据存在这儿,队列的1到4号成员成员规定好动作,比如把它移动到(90, 60),然后队列成员内部自己确定自己的位置,这样,我们只要宏观的控制队列就行了,一旦有了第5个成员,那就把第一个移动下删掉(实际上直接删掉就可以),然后python会自动对队列重新排序——del veh[0]之后,veh[1]就自动别成了veh[0],然后它就会自动移动到(90, 60),从他开始的位置上,至于其余的,也类似,veh[5]变成veh[4],根据veh[4]的要求,它就会自动移动到它该到的地方去。 关键代码如下: 这个是Veh类:

  1. class veh():   
  2.     ”’veh class, each will print a veh’s info  
  3.     ”’  
  4.   
  5.     def __init__(self, vehtype, speed, acce, lane, weight, space, datetime):   
  6.         ”’init object  
  7.  
  8.         a para’s expamle:  
  9.  
  10.         vehtype:    1           (int)  
  11.         speed:      65          (int)  
  12.         acce:       939         (int)  
  13.         lane:       1           (int)  
  14.         weight:     (790, 770)  (tuple of int)  
  15.         space:      2564        (int)  
  16.         datetime:               (a standard datetime object)  
  17.         ”’  
  18.   
  19.         self.vehtype    = vehtype   
  20.         self.speed      = speed   
  21.         self.acce       = acce   
  22.         self.weight     = weight   
  23.         self.space      = space   
  24.         self.datetime   = datetime  
  25.   
  26.         if lane == 1:   
  27.             self.x = 90   
  28.             self.y = 720   
  29.         else:   
  30.             self.x = 960 - 90 - 345   
  31.             self.y = -100   
  32.   
  33.         self.color  = (255, 255, 255)   
  34.   
  35.     def buildstring(self):   
  36.         ”’build string  
  37.  
  38.         make strings like this:  
  39.         self.str1 = ‘车型: 2轴车    时间: 2012.7.21 13:04:09′  
  40.         self.str2 = ‘车速: 83 km/h    加速度: 0 mm/s^2′  
  41.         self.str3 = ‘轴重: 800,, 800 kg’  
  42.         self.str4 = ‘轴距: 2423 mm’  
  43.         ”’  
  44.   
  45.         self.str1 = u’车型: {0}轴车 时间: {1}’.format(self.vehtype, self.datetime.strftime(‘%y.%m.%d %h:%m:%s’))   
  46.         self.str2 = u’车速: {0} km/h  加速度: {1} mm/s^2′.format(self.speed, self.acce)   
  47.         self.str3 = u’轴重: {0}, {1} kg’.format(self.weight[0], self.weight[1])   
  48.         self.str4 = u’轴距: {0} mm’.format(self.space)   
  49.   
  50.     def buildtextsurface(self):   
  51.         ”’bulid text surfaces  
  52.  
  53.         make surfaces like this:  
  54.         self.surface1 = fone.render(‘车型 … ‘, true, (255, 255, 255))  
  55.         …  
  56.         max of width: 340+  
  57.         height: 23  
  58.  
  59.         ”’  
  60.   
  61.         font = pygame.font.font(‘minijxh.ttf’, 20)   
  62.   
  63.         self.surface1 = font.render(self.str1, trueself.color)   
  64.         self.surface2 = font.render(self.str2, trueself.color)   
  65.         self.surface3 = font.render(self.str3, trueself.color)   
  66.         self.surface4 = font.render(self.str4, trueself.color)   
  67.         self.back_surface = pygame.image.load(‘rect_resize.jpg’).convert()   
  68.   
  69.     def up(self, movespeed, top, screen, time):   
  70.         ”’move veh up to top  
  71.  
  72.         para’s explantion:  
  73.         movespeed: speed of move, pixel/s, int  
  74.         top: the end of move, you just need to tell me the y coord, int  
  75.         ”’  
  76.   
  77.         time = float(time) / 1000.0 # conver from ms to s   
  78.         distance = movespeed * time  
  79.   
  80.         screen.blit(self.back_surface, (self.x - 5, self.y - 5))   
  81.         screen.blit(self.surface1, (self.x, self.y))   
  82.         screen.blit(self.surface2, (self.x, self.y + 23))   
  83.         screen.blit(self.surface3, (self.x, self.y + 23 * 2))   
  84.         screen.blit(self.surface4, (self.x, self.y + 23 * 3))   
  85.   
  86.         if self.y < top + 1:   
  87.             return 0   
  88.         else:   
  89.             self.y = self.y - distance   
  90.             return 1   
  91.   
  92.     def down(self, movespeed, bottom, screen, time):   
  93.         ”’move veh down to bottom  
  94.  
  95.         para’s explantion:  
  96.         movespeed: speed of move, pixel/s, int  
  97.         bottom: the end of move, you just need to tell me the y coord, int  
  98.         ”’  
  99.   
  100.         time = float(time) / 1000.0 # conver from ms to s   
  101.         distance = movespeed * time  
  102.   
  103.         screen.blit(self.back_surface, (self.x - 5, self.y - 5))   
  104.         screen.blit(self.surface1, (self.x, self.y))   
  105.         screen.blit(self.surface2, (self.x, self.y + 23))   
  106.         screen.blit(self.surface3, (self.x, self.y + 23 * 2))   
  107.         screen.blit(self.surface4, (self.x, self.y + 23 * 3))   
  108.   
  109.         if self.y > bottom - 1:   
  110.             return 0   
  111.         else:   
  112.             self.y = self.y + distance   
  113.             return 1  

 
这个是主程序:

  1. if __name__ == ‘__main__‘:   
  2.   
  3.     # format = ‘%y, %m, %d, %h, %m, %s, %f’   
  4.     # s = ’2013, 5, 24, 13, 7, 54, 100′   
  5.     # dt = datetime.datetime.strptime(s, format)   
  6.   
  7.     screen = pygame.display.set_mode((960, 720), hwsurface | doublebuf, 32)   
  8.     pygame.display.set_caption(u’车速车载实时图像’.encode(‘utf-8′))   
  9.     background = pygame.image.load(“road_shot_resize.jpg”).convert()   
  10.     screen.blit(background, (0, 0))   
  11.   
  12.     clock = pygame.time.clock()   
  13.   
  14.     vehs1 = []   
  15.     vehs2 = []   
  16.   
  17.     while true:   
  18.   
  19.         screen.blit(background, (0, 0))   
  20.   
  21.         st = time.clock()   
  22.   
  23.         for event in pygame.event.get():   
  24.             if event.type == quit:   
  25.                 exit()   
  26.   
  27.         ctime = clock.tick(100)   
  28.   
  29.         newveh = getveh()   
  30.   
  31.         if newveh[0] == 0:   
  32.             pass  
  33.         elif newveh[4] == 1:   
  34.             vehs1.append(veh(newveh[1], newveh[2], newveh[3], newveh[4], newveh[5], newveh[6], newveh[7]))   
  35.             vehs1[-1].buildstring()   
  36.             vehs1[-1].buildtextsurface()   
  37.         else:   
  38.             vehs2.append(veh(newveh[1], newveh[2], newveh[3], newveh[4], newveh[5], newveh[6], newveh[7]))   
  39.             vehs2[-1].buildstring()   
  40.             vehs2[-1].buildtextsurface()   
  41.   
  42.         if len(vehs1) == 5:   
  43.             vehs1[0].up(400, -100, screen, ctime)   
  44.             del vehs1[0]   
  45.         else:   
  46.             pass  
  47.   
  48.         if len(vehs1) > 0:   
  49.             vehs1[0].up(400, 60, screen, ctime)   
  50.   
  51.         if len(vehs1) > 1:   
  52.             vehs1[1].up(400, vehs1[0].y + 102 + 30, screen, ctime)   
  53.   
  54.         if len(vehs1) > 2:   
  55.             vehs1[2].up(400, vehs1[1].y + 102 + 30, screen, ctime)   
  56.   
  57.         if len(vehs1) > 3:   
  58.             vehs1[3].up(400, vehs1[2].y + 102 + 30, screen, ctime)   
  59.   
  60.         if len(vehs2) == 5:   
  61.             vehs2[0].down(400, 820, screen, ctime)   
  62.             del vehs2[0]   
  63.         else:   
  64.             pass  
  65.   
  66.         if len(vehs2) > 0:   
  67.             vehs2[0].down(400, 720 - 60 - 102, screen, ctime)   
  68.   
  69.         if len(vehs2) > 1:   
  70.             vehs2[1].down(400, vehs2[0].y - 102 - 30, screen, ctime)   
  71.   
  72.         if len(vehs2) > 2:   
  73.             vehs2[2].down(400, vehs2[1].y - 102 - 30, screen, ctime)   
  74.   
  75.         if len(vehs2) > 3:   
  76.             vehs2[3].down(400, vehs2[2].y - 102 - 30, screen, ctime)   
  77.   
  78.         pygame.display.flip()  

 
下面说下一个遗留问题,我希望用wx来呈现这个画面,因为整个监控系统是一体的,固然我可以在监控车速车载的时候用pygame建立窗口,但是我在退出系统的时候希望能把所有监控系统的窗口都退掉,或者说当我wx.Exit()的时候,我想把所有已打开窗口都关掉,怎么办?其实也很简单,照常建窗口就行了,先wx.Frame.__init__(),再pygame.display.set_mode()就ok,不用想得太复杂,虽然这样在退出的时候可以看到控制台会弹出个Exception,但是我用pyw打开,用户看不到,也感觉不到,也不影响正常使用,我就懒得管了。 完整代码在我的Github上可以看到,链接是:https://github.com/MatheMatrix/pyGameAnimation 我为了保险起见用了自己下的字体,一般用微软雅黑或者宋体其实就行,server是个广播数据用的,会随机“生成”一些车辆,client可以用来检测收没收到,演示的时候打开server和veh就行。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">

你可以管理本篇文章的订阅。

Post Navigation