VB中的窗口位图

1. 影响VB窗口中位图的属性

1) BackColor属性:该属性确定窗口背景颜色。

2) Picture属性:该属性用于作为窗口背景的图片,在窗口内部,该属性封装了一个BITMAPGDI对象。

3) hDCImageAutoReDraw属性

a) 如果设置为AutoReDraw(True) 则:

Ø hDC1个内存DCImage属性值是选入hDC的位图句柄,此时GetCurrentObject(hDC,OBJ_BITMAP)=Image(朋友们自行验证)。

Ø 在窗口输出操作代码PrintCircle输出到内存DC中,然后再从内存DC拷贝到目标窗口。

Ø VB没有提供目标窗口的DC,如果需要目标窗口的DC,需要使用GetDC获取,使用ReleaseDC释放。

Ø 如果使用API输出hDC输出后,必须使用Refresh输出反映到目标窗口,如果使用VB自带的绘图及文字输出方法,则不需要使用Refresh

Ø 不会产生Paint事件,对应于WindowsPaint消息,只是简单的将Image内容拷贝到目标窗口。取代之,是在运行开始,会产生Show事件,可以在Show事件。

Ø 如果使用APIGetDIBits方法,将获取窗口的前景及背景内容

Ø 事实上,AutoReDraw(True)时,窗口绘画就是一种双缓冲机制,但此机制有缺陷,其可绘图空间VB被限制和窗口尺寸一致,无法大于窗口尺寸。

b) 如果设置为非AutoReDraw (False) 则:

Ø hDC一个和窗口关联的设备DC

Ø Image属性仍然和一个位图对象关联,只是这个位图的内容BackColor属性Picture属性决定,每次BackColor或者Picrure改变,则会重新生成Image对应的位图对象。BackColor属性Picture不能完全填充窗口时候填充Picture之外的部分。

Ø Image对象将作为目标窗口的背景。CLS操作,就是讲Image对象内容拷贝到目标窗口。

Ø 对应于WindowsPaint消息,将产生VBPaint事件,VB程序一般在该事件中,提供绘画窗口的代码,实现输出

Ø 如果使用APIGetDIBits方法,只能获取窗口的背景内容BackColorPicture属性相关)。AutoReDraw (False)时,如何获取前景的内容,后续介绍中将给出代码。)

Ø

无论AutoReDraw为何,当窗口尺寸改变时,将重建Image,以使得Imge的大小和窗口一致

c) AutoReDrawTrue变为False,则True状态下的绘画输出,在变为AutoReDraw(False)后,绘图输出将成为背景的一部分,此Cls,将不能清除True时的绘画输出;要清除True时的绘图输出,则只再设置AutoReDraw(True)

d) AutoReDrawFalse变为True VB会使用BackColorPicture属性值重新加载背景,前景将被取消

2. 获取完整的窗口位图数据:

AutoReDraw(True)时,Image实际上是一个和窗口内容一致的位图句柄,可以直接将Image属性直接赋值给另一个控件或窗口的Picture属性,或者以Image属性作为句柄,使用API调用获取窗口内容数据;此时,一般都能得到窗口背景及前景的位图内容

Picture2.Picrure=Picture1.Image ‘Picture1显示内容拷贝到Picture2Picrure属性

或者:

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中进行显示显示时,我们使用Pic2Image属性,使用该属性能将拷贝入的位图保持住。

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

相关文章

Format[$] ( expr [ , fmt ] ) format 返回变体型 format$ 强...
VB6或者ASP 格式化时间为 MM/dd/yyyy 格式,竟然没有好的办...
在项目中添加如下代码:新建窗口来显示异常信息。 Namespace...
转了这一篇文章,原来一直想用C#做k3的插件开发,vb没有C#用...
Sub 分列() ‘以空格为分隔符,连续空格只算1个。对所选...
  窗体代码 1 Private Sub Text1_OLEDragDrop(Data As Dat...