wxPython:一曲MFC的挽歌,理想主义的绝唱( 九 )
文章图片
【wxPython:一曲MFC的挽歌,理想主义的绝唱】6.3.定时器和线程
在一个桌面程序中 , GUI线程是主线程 , 其他线程若要更新显示内容 , Tkinter使用的是类型对象 , PyQt使用的信号和槽机制 , wxPython则相对原始:它允许子线程更新GUI , 但需要借助于wx.CallAfter()函数 。
这个例子里面设计了一个数字式钟表 , 一个秒表 , 秒表显示精度十分之一毫秒 。 从代码设计上来说没有任何难度 , 实现的方法有很多种 , 可想要达到一个较好的显示效果 , 却不是一件容易的事情 。 请注意体会wx.CallAfter()的使用条件 。
importwximporttimeimportthreadingclassMainFrame(wx.Frame):"""桌面程序主窗口类"""def__init__(self):"""构造函数"""wx.Frame.__init__(self,parent=None,style=wx.CAPTION|wx.SYSTEM_MENU|wx.CLOSE_BOX|wx.MINIMIZE_BOX|wx.SIMPLE_BORDER)self.SetTitle('定时器和线程')self.SetIcon(wx.Icon('res/wx.ico',wx.BITMAP_TYPE_ICO))self.SetBackgroundColour((224,224,224))self.SetSize((320,300))self._init_ui()self.Center()def_init_ui(self):"""初始化界面"""font=wx.Font(30,wx.DECORATIVE,wx.FONTSTYLE_NORMAL,wx.FONTWEIGHT_NORMAL,False,'Monaco')self.clock=wx.StaticText(self,-1,'08:00:00',pos=(50,50),size=(200,50),style=wx.TE_CENTER|wx.SUNKEN_BORDER)self.clock.SetForegroundColour(wx.Colour(0,224,32))self.clock.SetBackgroundColour(wx.Colour(0,0,0))self.clock.SetFont(font)self.stopwatch=wx.StaticText(self,-1,'0:00:00.00',pos=(50,150),size=(200,50),style=wx.TE_CENTER|wx.SUNKEN_BORDER)self.stopwatch.SetForegroundColour(wx.Colour(0,224,32))self.stopwatch.SetBackgroundColour(wx.Colour(0,0,0))self.stopwatch.SetFont(font)self.timer=wx.Timer(self)self.Bind(wx.EVT_TIMER,self.on_timer,self.timer)self.timer.Start(50)self.Bind(wx.EVT_KEY_DOWN,self.on_key_down)self.sec_last=Noneself.is_start=Falseself.t_start=Nonethread_sw=threading.Thread(target=self.StopWatchThread)thread_sw.setDaemon(True)thread_sw.start()defon_timer(self,evt):"""定时器函数"""t=time.localtime()ift.tm_sec!=self.sec_last:self.clock.SetLabel('%02d:%02d:%02d'%(t.tm_hour,t.tm_min,t.tm_sec))self.sec_last=t.tm_secdefon_key_down(self,evt):"""键盘事件函数"""ifevt.GetKeyCode()==wx.WXK_SPACE:self.is_start=notself.is_startself.t_start=time.time()elifevt.GetKeyCode()==wx.WXK_ESCAPE:self.is_start=Falseself.stopwatch.SetLabel('0:00:00.00')defStopWatchThread(self):"""线程函数"""whileTrue:ifself.is_start:t=time.time()-self.t_startti=int(t)wx.CallAfter(self.stopwatch.SetLabel,'%d:%02d:%02d.%.02d'%(ti//3600,ti//60,ti%60,int((t-ti)*100)))time.sleep(0.02)if__name__=='__main__':app=wx.App()frame=MainFrame()frame.Show()app.MainLoop()代码运行界面如下图所示 。 界面上方的时钟一直再跑 , 下方的秒表则是按键启动或停止 。
文章图片
6.4.DC绘图
DC是DeviceContext的缩写 , 字面意思是设备上下文——我一直不能正确理解DC这个中文名字 , 也找不到更合适的说法 , 所以 , 我坚持使用DC而不是设备上下文 。 DC可以在屏幕上绘制点线面 , 当然也可以绘制文本和图像 。 事实上 , 在底层所有控件都是以位图形式绘制在屏幕上的 , 这意味着 , 我们一旦掌握了DC这个工具 , 就可以自己创造我们想要的控件了
DC有很多种 , PaintDC , ClientDC , MemoryDC等 。 通常 , 我们可以使用ClientDC和MemoryDC , PaintDC是发生重绘事件(wx.EVT_PAINT)时系统使用的 。 使用ClientDC绘图时 , 需要记录绘制的每一步工作 , 不然 , 系统重绘时会令我们前功尽弃——这是使用DC最容易犯的错误 。
importwxclassMainFrame(wx.Frame):"""桌面程序主窗口类"""def__init__(self):"""构造函数"""wx.Frame.__init__(self,parent=None,style=wx.CAPTION|wx.SYSTEM_MENU|wx.CLOSE_BOX|wx.MINIMIZE_BOX|wx.SIMPLE_BORDER)self.SetTitle('使用DC绘图')self.SetIcon(wx.Icon('res/wx.ico',wx.BITMAP_TYPE_ICO))self.SetBackgroundColour((224,224,224))self.SetSize((800,480))self._init_ui()self.Center()def_init_ui(self):"""初始化界面"""self.palette=wx.Panel(self,-1,style=wx.SUNKEN_BORDER)self.palette.SetBackgroundColour(wx.Colour(0,0,0))btn_base=wx.Button(self,-1,'文字和图片',size=(100,-1))sizer_max=wx.BoxSizer()sizer_max.Add(self.palette,1,wx.EXPAND|wx.LEFT|wx.TOP|wx.BOTTOM,5)sizer_max.Add(btn_base,0,wx.ALL,20)self.SetAutoLayout(True)self.SetSizer(sizer_max)self.Layout()btn_base.Bind(wx.EVT_BUTTON,self.on_base)self.palette.Bind(wx.EVT_MOUSE_EVENTS,self.on_mouse)self.palette.Bind(wx.EVT_PAINT,self.on_paint)self.xy=Noneself.lines=list()self.img=wx.Bitmap('res/forever.png',wx.BITMAP_TYPE_ANY)self.update_palette()defon_mouse(self,evt):"""移动鼠标画线"""ifevt.EventType==10030:#左键按下self.xy=(evt.x,evt.y)elifevt.EventType==10031:#左键弹起self.xy=Noneelifevt.EventType==10036:#鼠标移动ifself.xy:dc=wx.ClientDC(self.palette)dc.SetPen(wx.Pen(wx.Colour(0,224,0),2))dc.DrawLine(self.xy[0],self.xy[1],evt.x,evt.y)self.lines.append((self.xy[0],self.xy[1],evt.x,evt.y))self.xy=(evt.x,evt.y)defon_base(self,evt):"""DC基本方法演示"""img=wx.Bitmap('res/forever.png',wx.BITMAP_TYPE_ANY)w,h=self.palette.GetSize()dc=wx.ClientDC(self.palette)dc.SetPen(wx.Pen(wx.Colour(224,0,0),1))dc.SetBrush(wx.Brush(wx.Colour(0,80,80)))dc.DrawRectangle(10,10,w-22,h-22)dc.DrawLine(10,h/2,w-12,h/2)dc.DrawBitmap(img,10,10)dc.SetTextForeground(wx.Colour(224,224,224))dc.SetFont(wx.Font(16,wx.FONTFAMILY_DEFAULT,wx.FONTSTYLE_NORMAL,wx.FONTWEIGHT_NORMAL,False,'ComicSansMS'))dc.DrawText('霜重闲愁起',100,360)dc.DrawRotatedText('春深风也疾',400,360,30)defon_paint(self,evt):"""响应重绘事件"""dc=wx.PaintDC(self.palette)self.paint(dc)defupdate_palette(self):"""刷新画板"""dc=wx.ClientDC(self.palette)self.paint(dc)defpaint(self,dc):"""绘图"""dc.Clear()dc.SetPen(wx.Pen(wx.Colour(0,224,0),2))forlineinself.lines:dc.DrawLine(line[0],line[1],line[2],line[3])if__name__=='__main__':app=wx.App()frame=MainFrame()frame.Show()app.MainLoop()代码运行界面如下图所示 。
- 中兴超越中兴:夯实第一曲线 发力第二曲线
- 抖音回首大唐盛世千百年逢君天涯不过一瞬间一曲悠扬沧海复桑田江湖故人念是什么歌 歌曲分享
- Facebook|Facebook 大宕机:远程工作的一曲悲歌
- dns|Facebook 大宕机:远程工作的一曲悲歌
- 独家|腾讯音乐:一曲肝肠断,美股何处觅知音?
- 抖音江上一曲低诵晚风唱出心伤才知情浓鸳鸯离散谁知其中饱尝辛酸谁人能懂是什么歌 歌曲分享