VB中的窗口位图

来源:互联网 发布:房产销售提成软件 编辑:程序博客网 时间:2024/06/06 16:38

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,0, mImgLine,ImgData(0),bmpInfoHeader,BI_RGB)

                   nLines=GetDiBits(.Hdc,Picture2.Image,0, mImgLine,ImgData(0),bmpInfoHeader,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, 0, 0, nWidth, nHeight, hDCx, 0, 0, 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, 0, nHeight, 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, 0, BitmapInfo.bmiHeader.biHeight, ImgData(0), BitmapInfo, BI_RGB

如果Pic2.Image改为Pic1.Image则,将Pic1的彩色改变为黑白

    Pic2.Refresh

   

End Sub