VB中的窗口位图
1. 影响VB窗口中位图的属性 1) BackColor属性:该属性确定窗口背景颜色。 2) Picture属性:该属性用于作为窗口背景的图片,在窗口内部,该属性封装了一个BITMAP的GDI对象。 3) hDC、Image及AutoReDraw属性: a) 如果设置为AutoReDraw(True) 则: ? hDC为1个内存DC,Image属性值是选入hDC的位图句柄,此时GetCurrentObject(hDC,OBJ_BITMAP)=Image(朋友们自行验证)。 ? 在窗口输出操作代码入Print、Circle等输出到内存DC中,然后再从内存DC拷贝到目标窗口。 ? VB没有提供目标窗口的DC,如果需要目标窗口的DC,需要使用GetDC获取,使用ReleaseDC释放。 ? 如果使用API输出到hDC,输出后,必须使用Refresh将输出反映到目标窗口,如果使用VB自带的绘图及文字输出方法,则不需要使用Refresh。 ? 不会产生Paint事件,对应于Windows的Paint消息,只是简单的将Image的内容拷贝到目标窗口。取代之,是在运行开始,会产生Show事件,可以在Show事件。 ? 如果使用API的GetDIBits方法,将获取窗口的前景及背景内容。 ? 事实上,AutoReDraw(True)时,窗口绘画就是一种双缓冲机制,但此机制有缺陷,其可绘图空间VB被限制和窗口尺寸一致,无法大于窗口尺寸。 b) 如果设置为非AutoReDraw (False) 则: ? hDC是一个和窗口关联的设备DC ? Image属性仍然和一个位图对象关联,只是这个位图的内容由BackColor属性及Picture属性决定,每次BackColor或者Picrure改变,则会重新生成Image对应的位图对象。BackColor属性在Picture不能完全填充窗口时候填充Picture之外的部分。 ? Image对象将作为目标窗口的背景。CLS操作,就是讲Image对象内容拷贝到目标窗口。 ? 对应于Windows的Paint消息,将产生VB的Paint事件,VB程序一般在该事件中,提供绘画窗口的代码,实现输出。 ? 如果使用API的GetDIBits方法,只能获取窗口的背景内容(BackColor及Picture属性相关)。(AutoReDraw (False)时,如何获取前景的内容,后续介绍中将给出代码。) ? 无论AutoReDraw为何,当窗口尺寸改变时,将重建Image,以使得Imge的大小和窗口一致 c) AutoReDraw由True变为False,则True状态下的绘画输出,在变为AutoReDraw(False)后,绘图输出将成为背景的一部分,此Cls,将不能清除True时的绘画输出;要清除True时的绘图输出,则只再设置AutoReDraw(True) d) AutoReDraw由False变为True: VB会使用BackColor及Picture属性值重新加载背景,前景将被取消 2. 获取完整的窗口位图数据: 在AutoReDraw(True)时,Image实际上是一个和窗口内容一致的位图句柄,可以直接将Image属性直接赋值给另一个控件或窗口的Picture属性,或者以Image属性作为句柄,使用API调用获取窗口内容数据;此时,一般都能得到窗口背景及前景的位图内容。 Picture2.Picrure=Picture1.Image ‘Picture1上显示的内容拷贝到Picture2的Picrure属性中 或者: With Picture1 nLines=GetDiBits(.Hdc,.Image,mImgLine,ImgData(0),bmpInfoHeader,BI_RGB) nLines=GetDiBits(.Hdc,Picture2.Image,BI_RGB) end with
但是,使用Image属性获取位图,是无法获取下面几种情况的位图的: 1) 在非AutoReDraw(False)时,使用Image属性只能得到背景的图像,使用VB绘图方法及在hDC(窗口或者控件的hDC属性)上使用API绘图输出,这些输出都不能通过Image属性获得。 2) 在AutoReDraw(True)时,如果绘图操作是使用API输出到窗口的DC(不是控件的hDC,是使用hDCx=GetDC()得到的窗口DC)中,则该部分的位图内容是无法通过Image属性获取。同时,读取Image属性值的时候,VB会重新使用Image的内容更新窗口显示,从而使得窗口丢失使用上述方法的前景的输出。 3) 如果窗口或者控件上,有别的控件,那么这些控件虽然显示在窗口上,但是是不能通过Image属性获得。 因此,要想获得窗口的所有位图,只有使用hWnd属性而获得真正的窗口DC(称之为hDCx),然后通过hDCx的位图句柄hBmp,再通过hBmp获取位图数据;但是问题没有这么简单,因为Windows不允许直接读取窗口DC的位图数据,因此,还得将窗口位图拷贝到内存位图中后,才能读取位图数据。以下是完整的使用DIB读取窗口位图的函数。 Private Function GetWindowBmp(hWnd As Long,BmpInfo As BitmapInfo,nBits As Long,Optional mOffset As Long = 0) As Byte() Dim hDCx As Long Dim hBmp As Long Dim r As Long Dim hMemDC As Long Dim nWidth As Long,nHeight As Long Dim Rect As Rect Dim ImgData() As Byte Dim mLine As Long Dim mLineBytes As Long
Call GetWindowRect(hWnd,Rect) nWidth = Rect.Right - Rect.Left nHeight = Rect.Bottom - Rect.Top
hDCx = GetDC(hWnd) hMemDC = CreateCompatibleDC(hDCx) hBmp = CreateCompatibleBitmap(hDCx,nWidth,nHeight) r = SelectObject(hMemDC,hBmp) r = BitBlt(hMemDC,nHeight,hDCx,vbSrcCopy)
With BmpInfo.bmiHeader .biSize = Len(BmpInfo.bmiHeader) .biWidth = nWidth .biHeight = nHeight .biPlanes = 1 .biBitCount = nBits .biCompression = BI_RGB End With
mLineBytes = (((nWidth * nBits) + &H1F) And &HFFFFFFE0) &H8
ReDim ImgData(mLineBytes * nHeight - 1 + mOffset) mLine = GetDIBits(hDCx,hBmp,ImgData(mOffset),BmpInfo,BI_RGB) GetWindowBmp = ImgData
DeleteDC hMemDC ReleaseDC hWnd,hDCx DeleteObject hBmp
End Function 该函数返回窗口hWnd上显示的所有位图数据的数组,位图数据在该数组的mOffset位置开始放置,mOffset前的字节为保留字节(后面将介绍这些保留字节的用途),参数BmpInfo是一个BitmapInfo的数据结构,调用时候只要定义,不需给结构成员赋值,函数会按照窗口的位图数据自动填充,函数的调用者,一般需要使用该结构返回的数据。
3. 对获取位图数据进行处理: 以下代码用于获取Pic1的位图数据到一个数组中,然后将其转换为灰度图像的数据,再将灰度 图像拷贝到Pic2中进行显示,显示时,我们使用Pic2的Image属性,使用该属性能将拷贝入的位图保持住。 Private Sub Command3_Click() Dim ImgData() As Byte Dim mLineBytes As Long Dim BitmapInfo As BitmapInfo Dim mLineBytesA As Long Dim mIdx As Long
Dim x As Long,y As Long,C As Long Dim mLineFromIdx As Long Dim mBytesPerPix As Long
ImgData = GetWindowBmp(Pic1.hWnd,BitmapInfo,32&) '获取Pic1窗口上显示的位图数据 With BitmapInfo.bmiHeader '计算每行字节数 mLineBytes = .biWidth * .biBitCount / 8 If mLineBytes Mod 4 <> 0 Then mLineBytesA = ((mLineBytes + 3) 4) * 4 Else mLineBytesA = mLineBytes End If mBytesPerPix = .biBitCount / 8 '每像素字节数
For y = 0 To .biHeight - 1 mIdx = mLineFromIdx For x = 0 To mLineBytes - 1 Step mBytesPerPix
C = ImgData(mIdx) C = (C + ImgData(mIdx + 1) + ImgData(mIdx + 2)) / 3
ImgData(mIdx) = C ImgData(mIdx + 1) = C ImgData(mIdx + 2) = C mIdx = mIdx + mBytesPerPix Next mLineFromIdx = mLineFromIdx + mLineBytesA Next End With
SetDIBits 0,Pic2.Image,BitmapInfo.bmiHeader.biHeight,BI_RGB ‘如果Pic2.Image改为Pic1.Image则,将Pic1的彩色改变为黑白 Pic2.Refresh
End Sub (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |