截图的原理很简单,首先将当前整个屏幕的图像给保存下来,再将截取的位图贴到全屏,然后通过鼠标的控制,来绘制选中区域的高亮和未选中区域的阴暗背景。
父窗口通过以下函数截取整个屏幕
def Get_Screen_Bmp(self): s = wx.GetDisplaySize() bmp = wx.EmptyBitmap(s.x, s.y) dc = wx.ScreenDC() memdc = wx.MemoryDC() memdc.SelectObject(bmp) memdc.Blit(0,0, s.x, s.y, dc, 0,0) memdc.SelectObject(wx.NullBitmap) return bmp
子窗口类:
class GrabFrame(wx.Frame): def __init__(self, frame): wx.Frame.__init__(self, frame, wx.NewId(), pos = (0, 0), size=wx.GetDisplaySize(), style=wx.NO_BORDER | wx.STAY_ON_TOP) ###################################全局变量######################################## self.firstPoint = wx.Point(0, 0)#记录截图的第一个点 self.lastPoint = wx.Point(0, 0)#记录截图的最后一个点 self.Started = False #记录是否按下鼠标左键 self.frame = frame self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM) self.Bind(wx.EVT_PAINT, self.OnPaint) self.Bind(wx.EVT_LEFT_DOWN, self.On_Mouse_LeftDown) self.Bind(wx.EVT_LEFT_UP, self.On_Mouse_LeftUp) self.Bind(wx.EVT_MOTION, self.On_Mouse_Move) def OnPaint(self, evt): dc = wx.GCDC(wx.BufferedPaintDC(self)) self.PaintUpdate(dc) def PaintUpdate(self, dc): rect = self.GetClientRect() color = wx.Colour(0, 0, 0, 120) #设置绘制截图区域时矩形的点 minX, minY = min(self.firstPoint.x, self.lastPoint.x), min(self.firstPoint.y, self.lastPoint.y) maxX, maxY = max(self.firstPoint.x, self.lastPoint.x), max(self.firstPoint.y, self.lastPoint.y) #画出整个屏幕的截图 dc.DrawBitmap(self.frame.grabBmp, 0, 0) #画出阴影部分(截取的部分不需要画) dc.SetPen(wx.Pen(color)) dc.SetBrush(wx.Brush(color)) dc.DrawRectangle(0, 0, maxX, minY) dc.DrawRectangle(maxX, 0, rect.width - maxX, maxY) dc.DrawRectangle(minX, maxY, rect.width - minX, rect.height - maxY) dc.DrawRectangle(0, minY, minX, rect.height - minY) if(self.Started == True): #画出截图区域的边框 dc.SetPen(wx.Pen(wx.Colour(255, 0, 0))) dc.SetBrush(wx.Brush(color, wx.TRANSPARENT)) dc.DrawRectangle(minX, minY, maxX - minX, maxY - minY) #显示信息 dc.SetBrush(wx.Brush(wx.Colour(255,0,0))) dc.DrawRectangleList([ (minX - 2, minY - 2, 5, 5), (maxX / 2 + minX / 2 - 2, minY - 2, 5, 5), (maxX - 2, minY - 2, 5, 5), (maxX - 2, maxY / 2 + minY / 2 - 2, 5, 5), (maxX - 2, maxY - 2, 5, 5), (maxX / 2 + minX / 2 - 2, maxY - 2, 5, 5), (minX - 2, maxY - 2, 5, 5), (minX - 2, maxY / 2 + minY / 2 - 2, 5, 5) ]) color = wx.Colour(0,0,0,180) dc.SetPen(wx.Pen(color)) dc.SetBrush(wx.Brush(color, wx.SOLID)) w,h = 140, 43 s = u'区域大小:'+str(maxX - minX)+'*'+str(maxY - minY) s += u'\n鼠标位置:('+str(self.lastPoint.x)+','+str(self.lastPoint.y)+')' dc.DrawRectangle(minX, minY-h-5 if minY -5 > h else minY+5, w, h) dc.SetTextForeground(wx.Colour(255,255,255)) dc.DrawText(s, minX+5, (minY-h-5 if minY-5 > h else minY + 5)+5) def On_Mouse_LeftDown(self, evt): self.Started = True self.firstPoint = evt.GetPosition() self.lastPoint = evt.GetPosition() def On_Mouse_LeftUp(self, evt): if(self.Started): self.lastPoint = evt.GetPosition() if(self.firstPoint.x == self.lastPoint.x)&(self.firstPoint.y == self.lastPoint.y): wx.MessageBox(u"区域设置不正确", "Error", wx.OK | wx.ICON_ERROR, self) self.Started = False self.firstPoint = wx.Point(0, 0)#记录截图的第一个点 self.lastPoint = wx.Point(0, 0)#记录截图的最后一个点 else: self.frame.bmp = self.frame.grabBmp.GetSubBitmap(wx.Rect( min(self.firstPoint.x, self.lastPoint.x), min(self.firstPoint.y, self.lastPoint.y), abs(self.firstPoint.x - self.lastPoint.x), abs(self.firstPoint.y - self.lastPoint.y) )) self.Close() self.frame.Show() def On_Mouse_Move(self, evt): if(self.Started): self.lastPoint = evt.GetPosition() self.NewUpdate() def NewUpdate(self): self.RefreshRect(self.GetClientRect(), True) self.Update()声明一下,这个实际上那个是创建了一个没有边框、置顶的窗口,整个截图实际上就是在客户区(整个屏幕)中贴图再选择区域。这里的frame是其父窗口
dc.DrawBitmap(self.frame.grabBmp, 0, 0)将父窗口得到的全屏的位图贴到客户区
最后就是通过wx.Bitmap的GetSubBitmap函数来选取整张位图的其中一个区域
父窗口通过以下函数截取整个屏幕
def Get_Screen_Bmp(self): s = wx.GetDisplaySize() bmp = wx.EmptyBitmap(s.x, s.y) dc = wx.ScreenDC() memdc = wx.MemoryDC() memdc.SelectObject(bmp) memdc.Blit(0,0, s.x, s.y, dc, 0,0) memdc.SelectObject(wx.NullBitmap) return bmp