VB与API学习笔记(6)绘图DC

DC操作同窗体一样,取得DC句柄,即hDC.也是Long型

一个窗体对应一个DC,没有DC的窗体(控件也叫窗体),可以根据它的句柄来创建一个DC(上升到对象概念)。

DC在内存中是很占资源的,所以没有必要时,要进行释放它。

DC与windowDC是不同上,windowDC包含最上面的非工作区(一般由系统控制),如上面的图。各自绘图的区域就限制了。

看一个例子:先看图:


是有点奇怪,绘图跑到了最上面:),因为用了windowDC


Option Explicit

'取得窗体客户区DC
Private Declare Function GetDC Lib "user32" (ByVal hwnd As Long) As Long

'释放DC
Private Declare Function ReleaseDC _
                Lib "user32" (ByVal hwnd As Long, _
                              ByVal hdc As Long) As Long

'取得窗体DC
Private Declare Function GetWindowDC Lib "user32" (ByVal hwnd As Long) As Long

'画多边形
Private Declare Function Polygon _
                Lib "gdi32" (ByVal hdc As Long, _
                             lpPoint As POINTAPI, _
                             ByVal nCount As Long) As Long

Private Type POINTAPI
    x As Long
    y As Long

End Type

Private Sub Command1_Click() '文本框上绘图

    Dim point(2) As POINTAPI

    point(0).x = 10
    point(0).y = 10
    point(1).x = 30
    point(1).y = 30
    point(2).x = 30
    point(2).y = 10

    Dim hdc As Long

    hdc = GetDC(Text1.hwnd)
    Polygon hdc, point(0), ByVal 3&
    ReleaseDC Text1.hwnd, hdc

End Sub

Private Sub Command2_Click() '在客户区上绘图

    Dim point(2) As POINTAPI

    point(0).x = 50
    point(0).y = 50
    point(1).x = 100
    point(1).y = 100
    point(2).x = 100
    point(2).y = 50
    Polygon Form1.hdc, point(0), ByVal 3&

End Sub



Private Sub Command3_Click()  '在整个窗体上绘多边形
    Dim point(2) As POINTAPI
    point(0).x = 10
    point(0).y = 10
    point(1).x = 30
    point(1).y = 30
    point(2).x = 30
    point(2).y = 10
    Dim hdc As Long
    hdc = GetWindowDC(Form1.hwnd)
    Polygon hdc, point(0), ByVal 3&
    ReleaseDC Form1.hwnd, hdc
End Sub

      可以看到DC与hwnd密切相关。有了hwnd才有DC,换言之:必须先有窗体才能有DC的存在。


      特殊的:hwnd为0时代表的是整个屏幕(也是一个窗体),所以GetDc(0)就是取得屏幕的DC,屏幕保护程序就可以用它了。


=============================================================================================


再来一个概念:CreateCompatibleDC  

建立兼容DC,有些称为建立存储器DC,或内存DC。


这是为什么呢?

有了DC和windowDc不是就好了么?


一个窗体对应一个DC,这是一个好事,让我们辨别了各自的区域,绘图时就不会搞错。

但是另一个麻烦来了:每操作一下DC,就会在对应的窗体上更新,频繁更新的结果就是屏幕不断地刷新,看到屏幕不断地闪烁

非常影响人的视觉和情绪。


于是CompatibleDC出来了,它不对应任何一个窗体,但它可以创建一个和窗体一模一样的数据结构的DC。创建的目的是什么呢?

就是先把频繁多次操作DC的动作先“画”到这个替身CompatibleDC上,画完后,再直接把CompatibleDC拷贝到DC上。

好了,这样多次的DC操作就简化成只更新一次,就不会造成频繁闪烁的情况。


可以说替身CompatibleDC就像我们的临时变量一样,完成了更新,它的使命就算完成了,就可以寿终正寝了。


所以,叫内存DC,是表明它与窗体是脱钩的,只单独存在于内存。故它的释放不是ReleaseDC,而是用DeleteDC来删除。

其实,如果,假如ComatibleDC有窗体联系的,它每次操作也会造成闪烁,正因为它是与窗体没有联系的,所以就没有效果显示出来。



定义:

Private Declare Function CreateCompatibleDCLib "gdi32" Alias "CreateCompatibleDC" (ByVal hdc As Long) As Long
Private Declare Function DeleteDC Lib "gdi32" Alias "DeleteDC" (ByVal hdc As Long) As Long

        hMemDC=CreateComatibleDC(hDC)   '根据已有的DC来创建内存DC 

        DeleteDC hMemDC


结论:可以把DC和ComatibleDC“看作”就是窗体本身。


===============================================================================================


非常重要的API

BitBlt :图像转移       Bit-Block Transfer 位块传输,就是把源矩形区域图像传输到目的矩形区域。

返回值:0失败,非0成功


'取得窗体客户区DC
Private Declare Function GetDC Lib "user32" (ByVal hwnd As Long) As Long

'图像转移
Private Declare Function BitBlt _
                Lib "gdi32" (ByVal hDestDC As Long, _
                             ByVal x As Long, _
                             ByVal y As Long, _
                             ByVal nWidth As Long, _
                             ByVal nHeight As Long, _
                             ByVal hSrcDC As Long, _
                             ByVal xSrc As Long, _
                             ByVal ySrc As Long, _
                             ByVal dwRop As Long) As Long
'hDestDC 目的DC,(x,y)目的DC的起始坐标
'(nWidth,nHeight)目的和源DC的矩形宽高
'hSrcDC  源DC,  (xSrc,ySrc)源DC的起始坐标
'dwRop 图像转换方式,vbSrcCopy 源拷贝方式

Private Sub Command1_Click() '体验图片转换功能
    BitBlt Me.hdc, 0, 0, Picture1.ScaleWidth / Screen.TwipsPerPixelX, Picture1.ScaleHeight / Screen.TwipsPerPixelY, Picture1.hdc, 0, 0, vbSrcCopy
'    BitBlt Picture1.hdc, 0, 0, Picture1.ScaleWidth, Picture1.ScaleHeight, Me.hdc, 0, 0, vbSrcCopy
End Sub

Private Sub Command2_Click() '抓屏功能
    Dim sDc As Long
    Me.Hide           '隐藏窗体本身
    DoEvents          '延迟,以便抓屏准备
    sDc = GetDC(0)
    Picture1.ScaleMode = vbPixels '和下面两句配套,都用像素
    Picture1.Width = Screen.Width    '和保存图片配套,这样图片就是整个图片,因为image只是视窗部分。
    Picture1.Height = Screen.Height
    Picture1.AutoRedraw = True     '内存持久,内存中要保留,
    '抓屏
    BitBlt Picture1.hdc, 0, 0, Screen.Width, Screen.Height, sDc, 0, 0, vbSrcCopy
    '保存图片
    Set Picture1.Picture = Picture1.Image  '关键,转到picture对象上
    SavePicture Picture1, "D:\3.jpg"
    ReleaseDC 0, sDc
    Picture1.AutoRedraw = False  '释放内存图像
    Me.Show
End Sub

      再回看一下为什么有picture1.autoredraw呢?

      这个就有点类似前面说的CompatibleDC即内存DC,极似双缓冲DC,就是把图像保存在内存DC中,这样图像就不会因此丢掉。

       但它占用资源,所以最后关闭重绘,相当于删除内存DC

      那为什么有时人消失图像呢?当这个窗体被挡住时,相当于被挡住的部分或全部在DC里面“绘制”,绘制成没有图像,所以这个时候DC

      就像相处曝光一样,被冲了没,DC里面就没有“内容”了,当然重显示的时候,就没有了。



hMemDC到DC的复制,不是它们的句柄进行赋值。

    而是用bitBlt进行图像转移:  BitBlt  DC,0,0,w,h,hMemDC,0,0,vbSrcCopy

======================================================================

画图的方式:


dwROP  :    Raster  OPeration code光栅操作码


      SrcCopy      源DC覆盖拷贝到目的DC   

      SrcPaint      源DC与目的DC进行Or运算

      SrcAnd         ...................................And....

      SrcInvert     ....................................Xor.....

       SrcErase         S And  (Not D)

      NotSrcCopy      Not S后覆盖到D

      NotSrcErase     Not(S or D)      

      MergeCopy       S与花色AND后,覆盖写到DC

      MergePaint       (NOT  S)  or   D

      PatCopy              花色覆盖写到目的DC

       PatPaint            源反相后与目的及花色进行OR         (Not S) or  D or P

       PatInvert           目的DC与花色进行Xor                     D Xor  P

       DstInvert           目的DC反相     Not  D

       Blackness        目的Dc变黑      0

       Whiteness       目的DC变白      1

(D表示目的DC,S表示源DC)



由此可看出DC就象一个画板,里面准备了画笔,位图,字体、区域等。根据这些素材和动作,画出一幅完美的图,就是窗体。

也有人说,DC就象一个万能的画板,可以随时画,也可随时擦掉。

上面的花色就是由一些对象组成:


             CreateBitmap   建立位图对象

Private Declare Function CreateBitmap Lib "gdi32" Alias "CreateBitmap" (ByVal nWidth As Long, ByVal nHeight As Long, ByVal nPlanes As Long, ByVal nBitCount As Long, lpBits As Any) As Long


             CreatePatternBrush   建立花色对象(画笔)

Private Declare Function CreatePatternBrush Lib "gdi32" Alias "CreatePatternBrush" (ByVal hBitmap As Long) As Long


         这两个API就建立了一个花色对象。但怎么用这个对象呢?

         前面bitblt中并没有指定花色对象的参数,它是怎么联系哪个花色对象的呢?

         为DC选用对象:    SelectObject

Private Declare Function SelectObject Lib "gdi32" Alias "SelectObject" (ByVal hdc As Long, ByVal hObject As Long) As Long

        这个就为某DC指定选用对象,于是就联系起来了,。返回值:DC中前一个同类型对象的handle

        意思是:要使用临时画笔,这个就替换了原来的画笔,但使用完后,删除后,怎么恢复原来的画笔呢?就是这个返回值,指向

同类型对象的前一个handle

         另外一个就是因为DC中很多对象,有些是不再使用的,为了节省资源,可以进行删除

        无论是位图或画笔,可以进行删除:DeleteObject 

Private Declare Function DeleteObject Lib "gdi32" Alias "DeleteObject" (ByVal hObject As Long) As Long

 

         下例是一个屏幕变暗及恢复例子,其实没啥用处,就是看一下各API是怎么用的。

        InvalidateRectAny就是恢复窗体原貌,重绘某区域。原因是:指定某矩形区域为“无效”后,系统就会不断向其区域发出“绘制”命令,使这一部分重新绘制。

        但这有什么用呢?因为重绘一个大的区域会浪费时间,效率不高,于是就用这个API对“关键的”、“常变”的区域进行指定并重绘,提高绘制效率。

         Private Declare Function InvalidateRect Lib "user32" Alias "InvalidateRect" (ByVal hwnd As Long, lpRect As RECT,ByVal bErase As Long) As Long

         最后一个参数是是否擦除背景,就是是否删除DC,一般为真:True


Private Declare Function GetDC Lib "user32" (ByVal hwnd As Long) As Long

Private Declare Function ReleaseDC _
                Lib "user32" (ByVal hwnd As Long, _
                              ByVal hdc As Long) As Long

Private Declare Function BitBlt _
                Lib "gdi32" (ByVal hDestDC As Long, _
                             ByVal x As Long, _
                             ByVal y As Long, _
                             ByVal nWidth As Long, _
                             ByVal nHeight As Long, _
                             ByVal hSrcDC As Long, _
                             ByVal xSrc As Long, _
                             ByVal ySrc As Long, _
                             ByVal dwRop As Long) As Long

Private Declare Function CreateBitmap _
                Lib "gdi32" (ByVal nWidth As Long, _
                             ByVal nHeight As Long, _
                             ByVal nPlanes As Long, _
                             ByVal nBitCount As Long, _
                             lpBits As Any) As Long

Private Declare Function CreatePatternBrush Lib "gdi32" (ByVal hBitmap As Long) As Long

Private Declare Function SelectObject _
                Lib "gdi32" (ByVal hdc As Long, _
                             ByVal hObject As Long) As Long

Private Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long

Private Declare Function InvalidateRectAsAny _
                Lib "user32" _
                Alias "InvalidateRect" (ByVal hwnd As Long, _
                                        lpRect As Any, _
                                        ByVal bErase As Long) As Long

Private Sub Command1_Click() '屏幕变暗

    Dim hOldPattern As Long, bBmp(0 To 15) As Byte

    Dim hBitmap     As Long, hPattern As Long, hDCScreen As Long

    Dim sx          As Long, sy As Long

    bBmp(0) = &H55: bBmp(2) = &HAA: bBmp(4) = &H55: bBmp(6) = &HAA
    bBmp(8) = &H55: bBmp(10) = &HAA: bBmp(12) = &H55: bBmp(14) = &HAA
    hBitmap = CreateBitmap(8, 8, 1, 1, bBmp(0)) '建立位图
    hPattern = CreatePatternBrush(hBitmap)      '根据位图建立画笔(花色)
    hDCScreen = GetDC(0)
    hOldPattern = SelectObject(hDCScreen, hPattern)  '选用画笔
    sx = Screen.Width / Screen.TwipsPerPixelX
    sy = Screen.Height / Screen.TwipsPerPixelY
    BitBlt hDCScreen, 0, 0, sx, sy, hDCScreen, 0, 0, vbMergeCopy  '图像转换
    SelectObject hDCScreen, hOldPattern              '恢复原来画笔
    ReleaseDC 0, hDCScreen
    DeleteObject hBitmap                            '删除位图
    DeleteObject hPattern                        '删除画笔(花色)

End Sub

Private Sub Command2_Click()
    InvalidateRectAsAny 0, ByVal 0&, True  '恢复原来屏幕(变明)

End Sub

       可以看到vbMergeCopy与花色的运算,是前面刚选进来的画笔(花色),用完就扔delete.根据选用时的handle恢复原来的花色。

        

             

======================================================================================================


认识Bitmap对象

bitmap不是位图么?一般我们看到的就是“图”,如果直接不用函数直接要来显示的画,就麻烦了,这个“图”文件中的表头消息、位图表消息,

点阵数据等很是麻烦。

一般用LoadPicture就轻易读出。实际上它是把Bitmap当作对象,返回的是一个对象的句柄。叫hBitmap(handle of Bitmap)

是有点怪!

看一下情况: Set  picture1.picture=loadpicture(位图)

这个就设置了图片,实际上是取得了hBitmap给picture属性。这个picture就是hBitmap

我们用: print   Picture1.picture            可以看到显示出来是一个长整形。

(注意:bmp,jpg,gif都是hBitmap,但ico,cur,wmf时就不是了)


可以由Bitmap的句柄hBitmap取得这个bitmap图的结构。


Private Declare Function GetObject Lib "gdi32" Alias "GetObjectA" (ByVal hObject As Long, ByVal nCount As Long, lpObject As Any) As Long


           根据一个对象的句柄,取得这个对象的结构。取回的结构在后面两个参数中。返回值:0失败,非0成功。


对于一个Bitmap对象,可以:

    dim   bm  as Bitmap

             GetObject  hBitmap,len(bm),bm   '返回值在bm中。


其中Bitmap类型定义:

Private Type BITMAP
        bmType As Long    '固定为0
        bmWidth As Long     '图的宽
        bmHeight As Long    '图的高
        bmWidthBytes As Long '多少二进制构成一个储存单元,通常为16(两字节)
        bmPlanes As Integer  '调色板数
        bmBitsPixel As Integer '每像素所占二进制位数(表示色彩丰富度)
        bmBits As Long         '位图二进位数据的起始位置
End Type

这样通过GetObject取回结构bm后。

      就可以用bm.bmwidth,bmheight取得这个图的宽和高,为后面的工作作准备。















  • 2
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值