返回列表 回复 发帖

原创转载 :: VB6 GDI+ 基础教程 Last updated:2009/12/11

原创转载 :: VB6 GDI+ 基础教程 Last updated:2009/12/11

18

评分次数

  • gxght1122

  • yimins

  • VB---NEW

  • VBProFan

  • blk661

  • beixue

  • cheaven

  • xuqin3

  • gbm

  • 513069906

  • szdan

  • snyga

  • ewqs

  • zzyong00

  • acmilan1984

  • reker

  • cnlamb

  • hwbwsb

本帖最后由 reker 于 2009-12-12 19:44 编辑

Visual Basic 6 GDI+ 入门教程[1] GDI+介绍

为了高亮我专门写了一个高亮器。。囧。。
Chrome的文本框真不是一点点的有问题,导致我用Firefox。。

引言:鉴于网上关于GDI+的教程都是.Net的,基本上没有VB6.0的,而这方面又很多人有需要,所以我就写一个Visual Basic 6 GDI+ 入门教程。
目标人群:所有能够较熟练使用VB的,对GDI+感兴趣或有GDI+编程需要的人。

1.What's GDI+

官方解释:GDI+是Windows XP中的一个子系统,它主要负责在显示屏幕和打印设备输出有关信息,它是一组通过C++类实现的应用程序编程接口。顾名思义,GDI+是以前版本GDI的继承者,出于兼容性考虑,Windows XP仍然支持以前版本的GDI,但是在开发新应用程序的时候,开发人员为了满足图形输出需要应该使用GDI+,因为GDI+对以前的Windows版本中GDI进行了优化,并添加了许多新的功能。
作为图形设备接口的GDI+使得应用程序开发人员在输出屏幕和打印机信息的时候无需考虑具体显示设备的细节,他们只需调用GDI+库输出的类的一些方法即可完成图形操作,真正的绘图工作由这些方法交给特定的设备驱动程序来完成,GDI+使得图形硬件和应用程序相互隔离,从而使开发人员编写设备无关的应用程序变得非常容易。

我的解释:GDI+其实就是一个绘图模块,用于在屏幕上输出各种需要的内容。

2.GDI+ DLL

GDI+的Dll在Windows XP+中默认存在,如果Windows XP以下系统需要使用GDI+,那么需要从微软网站上下载安装包。

3.使用GDI+

GDI+在.net Framework中默认集成,只要添加它的命名空间(System.Drawing.Drawing2D)就能够使用了;而GDI+在其它上面就没有那么容易了,例如VB6就需要添加GDI+的API。对于初学者,写一堆API可能比学GDI+用时还要长,不过我整理好了API到了一个模块,使用时候呢 只要在VB里面加载一下就可以啦!

附件:
http://www.vbgood.com/viewthread.php?tid=87356&page=4#pid481239
本帖最后由 reker 于 2009-9-17 21:51 编辑

Visual Basic 6 GDI+ 入门教程[2] GDI+初始化

现在先让我们了解下GDI+的绘图机制。

1.初始化、关闭GDI+

我们需要对GDI+进行初始化,才能使用它的各种功能。如果没有初始化,那么VB6就会莫名其妙的崩溃。呵呵。

当然程序结束了我们还要关闭GDI+释放内存。

2.Graphics

Graphics是GDI+基础。首先我们需要一个图形对象graphics(可以看作是画板),我们所有的东西都要画在这个上面。那么如何显示呢?不要急,我们可以通过GDI+内置函数从一个对象的DC(设备描述表)上创建graphics。这样我们操作graphics的时候就会显示在对象上。当然我们还可以从对象的hwnd中创建也可以从gdi+的图像(image)中创建。

3.绘图工具

有了画板,我们还要画笔、画刷才能画画 - -。画笔画刷呢,在gdi+中就叫做pen、brush。画笔pen只能画一个轮廓(画线),而画刷可以对一个东西进行填充(刷子)。这个就是一个基础 呵呵,很简单吧。

4.创建第一个VB6的 GDI+ 程序

首先,我们添加下GDI+模块;然后我们需要对窗体(以后可以是其它容器)属性进行设置:AutoRedraw=True,开启自动重绘;再把ScaleMode设置成3(Pixel像素),因为GDI+基础单位就是像素(当然可以用别的单位)

好 现在双击窗体,写入下面代码:

Dim Graphics As Long

Private Sub Form_Load()
    InitGdiplus
   
    GdipCreateFromHDC Me.HDC, Graphics
End Sub

Private Sub Form_Unload(Cancel As Integer)
    GdipDeleteGraphics Graphics '释放Graphics占用的内存

    TerminateGdiplus
End Sub
OK,F5运行。如果没有问题的话我们第一个最基础的GDI+程序已经完成了。这个基本的程序创建了一个graphics对象,当然什么还没有画呢。

通过这个程序,我们就大致了解VB6中GDI+如何初始化、关闭了。首先呢要启动GDI+,然后要创建一个graphics;关闭的时候也要做好扫地工作。

5.画线

线嘛,又不是填充,根据前面说的,我们需要一个pen。那么如何创建pen呢?呵呵,下面的代码就能创建一个pen(追加在Form_Load过程中的末尾):

   Dim Pen As Long
   GdipCreatePen1 &HFFFF0000, 1, UnitPixel, Pen
这里已经新建了一个pen。为什么是GdipCreatePen1而不是GdipCreatePen2什么的呢?你可以在代码里面输入“mgdip.”这样就列出了所有的GDI+函数。通过对象浏览器可以得知pen2是根据brush来创建pen的,现在不用。

&HFFFF0000:这里就是一个16进制的ARGB (Alpha,Red,Green,Blue——透明,红色,绿色,蓝色程度,255(&HFF)是完全,0(&H0)是完全不) 的数据。当然你可以输入10进制,只是16进制很方便,2个位就是一段,如&HFFFF0000就代表一个透明度是255(不透明),颜色是红色的一种颜色。如果你知道点绘图技巧就很容易用这个去写 呵呵~。同时我们还能看到gdi+过程是传址的,把pen传进去。为什么不用函数传出来呢?因为函数要传出一个标识,错误标识。一般如果成功了那么就返回的是0(Ok)。

好,现在已经拿到笔了,接下来就是用这个笔去画线了。通过查询可知有这么个API:GdipDrawLine,它的X1Y1,X2Y2是single型,继续找又发现GdipDrawLineI,它的坐标值都是Long型(我们一般用不到single,因此我们一般用GdipDrawLineI就行了)。根据它的参数名字 乱猜都能猜出来哪个参数代表什么了,于是我随便写了一句:GdipDrawLineI graphics, pen, 10, 10, 200, 100。注意:你需要把graphics和pen传进去,否则怎么画呢?不告诉它画在哪里~~,后面4个参数分别对应:起始点X、起始点Y、终点X、终点Y的坐标。当然扫地工作也要做好,删除pen的语句是GdipDeletePen;参数很简单,传pen进去即可。

综合起来,于是我们有了第一段真正绘制的GDI+ VB6程序,虽然它只画了一条线:

Dim Graphics As Long
Dim Pen As Long
   
Private Sub Form_Load()
    InitGdiplus
   
    GdipCreateFromHDC Me.HDC, Graphics
    GdipCreatePen1 &HFFFF0000, 1, UnitPixel, Pen
   
    GdipDrawLineI Graphics, Pen, 10, 10, 200, 100
End Sub

Private Sub Form_Unload(Cancel As Integer)
    GdipDeletePen Pen '删除这个笔(Pen)
    GdipDeleteGraphics Graphics '释放Graphics占用的内存

    TerminateGdiplus
End Sub
OK,F5运行。红线没有出来?^_^……注意了 我们是在Load中绘制的。GDI+绘制与VB自己语句绘制一样。我们需要让他自动重绘(窗体的AutoRedraw=True)或者放到Paint里面:)

终于……哈,一条红色的斜线出现了!
本帖最后由 reker 于 2009-9-17 21:52 编辑

Visual Basic 6 GDI+ 入门教程[3] 笔、刷子、矩形、椭圆绘制

好,我们已经学会如何画线了,那么后面的事情只要变通下都可以解决。不过变通前我还是得说几个基本的东西。

1.绘制,填充一个矩形

绘制一个整型长度的矩形,我们要用到GdipDrawRectangleI和GdipFillRectangleI。前者用pen画一个轮廓边框,后者用brush刷出一个填充区域。当然接下来就是如何创建刷子的问题了。GDI+中有多种刷子,有纯色刷子(创建:GdipCreateSolidFill),有渐变刷子(创建:GdipCreateLineBrush),还有纹理刷子,贴图刷子,路径刷子等等…………它们用于不同的方面。

(1)绘制一个矩形边框

首先,我们需要一个pen。

第一步,Dim!当然,我这样写了:Dim pen As Long;

第二步,创建一个红色的pen(线的粗细是1px):GdipCreatePen1 &HFFFF0000, 1, UnitPixel, pen。

pen创好了,接下来画矩形。这里我们用GdipDrawRectangleI来画矩形。画矩形跟画线可不一样,虽然指定坐标的都是4个参数,但是矩形里面四个参数分别是:X,Y,长,宽。OK,综合一下,代码如下:

Dim Graphics As Long
Dim Pen As Long
   
Private Sub Form_Load()
    InitGdiplus
   
    GdipCreateFromHDC Me.HDC, Graphics
   
    GdipCreatePen1 &HFFFF0000, 1, UnitPixel, Pen
    GdipDrawRectangleI Graphics, Pen, 30, 30, 100, 100
End Sub

Private Sub Form_Unload(Cancel As Integer)
    GdipDeletePen Pen
    GdipDeleteGraphics Graphics '释放Graphics占用的内存
   
    TerminateGdiplus
End Sub

现在我们就绘制了一个100*100的红色矩形边框。很简单吧,变通就是这样的。

(2)创建纯色刷子

任何刷子包括其它的GDI+元素基本上都是一个思路:我们首先要Dim一个long型变量储存刷子/其它元素的地址,然后再调用GDI+相关函数去创建出指定刷子/其它元素。现在来创建一个蓝色,透明度为&HAA的刷子,那么代码就是这样:

    Dim Brush As Long
    GdipCreateSolidFill &HAA0000FF, Brush
刷子就这样拿到了。当然不要忘记扫地工作:GdipDeleteBrush brush。

(3)用刷子填充一个矩形

很明显,函数里面找一下就会发现我们要的函数:GdipFillRectangleI。它与DrawRectangleI很类似,只不过把pen变成了brush,因为现在要刷上去嘛- -。这一步也是很好变通的。把前面的一翻整理之后我们得到了一个绘制矩形并填充(不如说先填充再画边框,至于原因你可以自己颠倒一下顺序看下结果)的代码(注意 填充色是有透明度的):

Dim Graphics As Long
Dim Pen As Long, Brush As Long
   
Private Sub Form_Load()
    InitGdiplus
   
    GdipCreateFromHDC Me.HDC, Graphics
   
    GdipCreatePen1 &HFFFF0000, 1, UnitPixel, Pen
    GdipCreateSolidFill &HAA0000FF, Brush
   
    GdipFillRectangleI Graphics, Brush, 30, 30, 100, 100
    GdipDrawRectangleI Graphics, Pen, 30, 30, 100, 100
End Sub

Private Sub Form_Unload(Cancel As Integer)
    GdipDeletePen Pen
    GdipDeleteBrush Brush
    GdipDeleteGraphics Graphics '释放Graphics占用的内存
   
    TerminateGdiplus
End Sub

一样很简单吧!GDI+就是那么简单,只要懂了它的“工作机制”~!

(4)渐变刷子

渐变色很Cool,纯VB代码却要很多,还好,GDI+有一个方便的渐变刷子函数——GdipCreateLineBrush。看参数,发现不一样:

Function GdipCreateLineBrush(Point1 As POINTF, Point2 As POINTF, Color1 As Long, Color2 As Long, WrapMode As WrapMode, LineGradient As Long) As GpStatus
虽然复杂。。不过又很容易理解:Point1是一个PointF结构,它储存了坐标的X,Y(浓缩哈),代表起始位置…………咿,这是刷子啊,怎么也有起始、中止……?其实呢,这是渐变的起始、中止位置。不过一般情况下我们的起始中止位置是和绘制的图形一致的。Point2一样,代表了终点。渐变就在这两个点中“展开”。注意咯,现在是坐标点,不是长宽值啦!Color1自然就是起始颜色,Color2嘛 第二颜色。WrapMode就是填充方向,最后一个参数自然就是传回brush咯。

于是我们又开始写程序了,这次是创建一个蓝色>红色,纵向的刷子。绘制图形免去,如果想看效果请自己添加drawrectangle(如果还要使用point画矩形请注意啦,rectangle里面 后面参数是接受长宽,而刷子里面接受的是点……知道区别和解决方法了么?减呗!)……,这主要让你知道刷子的“运作模式”呵呵。

    Dim Brush As Long
    Dim p1 As POINTF, p2 As POINTF
    p1.X = 10
    p1.Y = 10
    p2.X = 100
    p2.Y = 100
    GdipCreateLineBrush p1, p2, &HFF0000FF, &HFFFF0000, WrapModeTileFlipy, Brush
2.绘制椭圆

椭圆,想想也不会跟rectangle画法相差到哪里去。事实的确如此。下面就是一个绘制渐变椭圆的代码,解释免了吧,应该是很容易理解的。

Dim Graphics As Long
Dim Brush As Long
   
Private Sub Form_Load()
    InitGdiplus
   
    GdipCreateFromHDC Me.HDC, Graphics
   
    Dim p1 As POINTF, p2 As POINTF
    p1.X = 10
    p1.Y = 10
    p2.X = 100
    p2.Y = 50
   
    GdipCreateLineBrush p1, p2, &H8AFF00FF, &HFFFF0000, WrapModeTileFlipXY, Brush
    GdipFillEllipseI Graphics, Brush, p1.X, p1.Y, p2.X - p1.X, p2.Y - p1.X '注意:类似的,绘制椭圆边框的语句是GdipDrawEllipseI
End Sub

Private Sub Form_Unload(Cancel As Integer)
    GdipDeleteBrush Brush
    GdipDeleteGraphics Graphics '释放Graphics占用的内存

    TerminateGdiplus
End Sub

3.反锯齿功能

不知你有没有发现,画出来的椭圆是很不圆滑的(虽然用VB自己绘制也是如此)。如此强大的GDI+怎么可能没有圆滑的功能呢?有!函数是GdipSetSmoothingMode。我们需要把它加在绘制内容之前。一般我们把它加在创建好graphics之后(注意:它是作用于graphics的,因此请不要还没初始化graphics就设置graphics的光滑属性- -)。经过一翻调整,我们得出了一个设置圆滑的语句:

GdipSetSmoothingMode Graphics,SmoothingModeAntiAlias
模式自然要设置成AntiAlias,AntiAlias顾名思义就是反锯齿(消除锯齿)。现在我们把这句话加到前面的椭圆程序中去,运行,如何,椭圆很光滑吧!同样,前面任何一个程序都可以这样加使gdi+画出来的东西看上去很平滑。
本帖最后由 reker 于 2009-9-17 21:52 编辑

Visual Basic 6 GDI+ 入门教程[4] 文字绘制

图形我们已经会画了,现在还有一个问题,就是怎么显示文字呢?这一篇我将介绍GDI+中绘制文字的推荐方法(感谢reker的修正)

1.GDI+中文字的必须要素

首先,与其它软件一样,GDI+中的文字也有格式。画文字有多种画法,但是无论如何,我们都需要创建一个FontFamily,这其中包含了字体类型的信息,包括字体名称、字体对齐方式(需要设置)等等。一般的画法然后还要从这个FontFamily创建一个Font,这个Font中包括字体样式(粗体、斜体)、字号等等,再后来我们调用一个函数把文字用这个Font显示出来~;路径画法(可以显示边框画法)则不需要创建字体,直接调用函数,字体的样式包括在函数里面了。

可见,GDI+中文字是需要一个FontFamily(一般是全局的),和一些Font(各种不同样式)以及文字组成的。

2.GDI+绘制文字

GDI+绘制文字有几种,下面将分别示例。

(1)标准画法:GdipDrawString

这是一般的画文字的办法,这种画法支持ClearTypeGridFit(还需要用语句再设置下),需要创建Font。

以下是主要绘图部分(窗体):

Option Explicit
Dim Graphics As Long, Brush As Long
Dim Fontfam As Long, strformat As Long, curFont As Long, rclayout As RECTF
   
Private Sub Form_Load()
    InitGdiplus
   
    GdipCreateFromHDC Me.HDC, Graphics
    GdipCreateFontFamilyFromName StrPtr("黑体"), 0, Fontfam
    GdipCreateStringFormat 0, 0, strformat
    GdipCreateSolidFill &HFFFF0000, Brush
    GdipSetStringFormatAlign strformat, StringAlignmentNear
    GdipCreateFont Fontfam, 15, FontStyle.FontStyleItalic, UnitPixel, curFont

    GdipSetTextRenderingHint Graphics, TextRenderingHintClearTypeGridFit

    rclayout.Left = 100
    rclayout.Top = 100
    rclayout.Right = 150
    rclayout.Bottom = 150
   
    GdipDrawString Graphics, StrPtr("Hellow world! 这是我们第一个GDI+文字~!!"), -1, curFont, rclayout, strformat, Brush
End Sub

Private Sub Form_Unload(Cancel As Integer)
    GdipDeleteFontFamily Fontfam
    GdipDeleteStringFormat strformat
    GdipDeleteFont curFont
    GdipDeleteBrush Brush
    GdipDeleteGraphics Graphics '释放Graphics占用的内存

    TerminateGdiplus
End Sub
可以看到这种画法思路:

1.创建FontFamily (StrPtr:获取字符串指针,这样就能支持中文了!这就是不用TLB的原因……)

2.创建stringFormat(一般也可以不创),设置样式

3.创建Font。其中一定要注意单位问题。否则不要问我进去14输出的怎么不是14px大小文字……这里我们字体样式也巧妙了下,虽然声明中可以改写为As FontStyle但是不推荐。于是我们写就写FontStyle.xxx这样又可读性高,又不会出错。

4.创建Brush(显示文字咯)

5.设置文字区域(RcLayout)

6.绘制图形

7.扫地工作

这样 完美地画出了字。

注意:rectf中虽然是right,bottom但是实际上是width height,大家不要被误导!

(2)路径画法:GdipAddPathString

这种画法一般用于绘制旋转文字、描边的文字等等。虽然可以设置graphics的圆滑设置,但是它画出来的文字依然不怎么清晰(相对于第一种来说)

窗体中:

Option Explicit

Dim Graphics As Long, Brush As Long, Pen As Long
Dim FontFam As Long, strFormat As Long, strPath As Long, rclayout As RECTL
   
Private Sub Form_Load()
    InitGdiplus
   
    GdipCreateFromHDC Me.HDC, Graphics
    GdipSetSmoothingMode Graphics, SmoothingModeAntiAlias

    GdipCreateFontFamilyFromName StrPtr("Verdana"), 0, FontFam
    GdipCreateStringFormat 0, 0, strFormat
    GdipSetStringFormatAlign strFormat, StringAlignmentNear
   
    GdipCreateSolidFill &HFFDEDEDE, Brush
    GdipCreatePen1 &HFF222222, 2, UnitPixel, Pen
   
    rclayout.Left = 10
    rclayout.Top = 10
    rclayout.Right = 200
    rclayout.Bottom = 150
   
    GdipCreatePath FillModeAlternate, strPath
    GdipAddPathStringI strPath, StrPtr("描边 0123"), -1, FontFam, FontStyle.FontStyleBold, 55, rclayout, strFormat
    GdipFillPath Graphics, Brush, strPath
    GdipDrawPath Graphics, Pen, strPath
End Sub

Private Sub Form_Unload(Cancel As Integer)
    GdipDeleteFontFamily FontFam
    GdipDeleteStringFormat strFormat
    GdipDeletePath strPath
    GdipDeleteBrush Brush
    GdipDeletePen Pen
   
    GdipDeleteGraphics Graphics '释放Graphics占用的内存

    TerminateGdiplus
End Sub

好 回来了 我们来比较一下这个画法有什么好处。

看出来了 它可以描边……恩 我不是在上面说了嘛 它还支持旋转、合并等等。

对了 我还说过“画出来不怎么清晰”,这里好像很好嘛!其实不然。如果你把描边去掉,单单FillPath,并且把字号减小 比如14,字体样式为普通,你就会发现不清晰了~!

它的过程是这样的:

1.首先前面部分和画普通文字一样 都需要创建FontFamily还有可选的创建字体对齐格式等等。

2.接下来路径画法不需要创建Font,我们需要创建(初始化)一个路径,否则可是什么都没有哦~

3.然后我们需要把文字增加到Path中去。

4.我们要FillPath填充这个路径 或者是DrawPath描出这个路径。如果是实心文字自然就是FillPath咯

5.最后别忘了释放Pen(如果有)和Brush(如果有) 以及最后一个Path。

(3)底层画法:GdipDrawDriverString

如名,底层画法。这种画法是最底层的绘制文字,底层到了……它不会自动转换字体(比如用Verdana绘制中文字体就不会显示出来) 由于不常使用,这里不贴画法了。
本帖最后由 reker 于 2009-9-17 21:53 编辑

Visual Basic 6 GDI+ 入门教程[5] 基础绘图小结

终于……我们的基础绘图部分可以先告一段落了。什么叫基础绘图?画线、画圈圈、画方块、画字……等等。我们来总结一下。

我们第一点就是总结DrawXXXX和FillXXXX。

1.DrawXXXX:描边可以这么说 例如DrawRectangle  DrawPath。我们都需要一个Pen(边框)来描绘它。

2.FillXXXX:填充。例如FillRectangle等等。我们需要的是Brush。

我们第二点总结平滑(反锯齿)——什么时候用GdipSetTextRenderingHint,什么时候用GdipSetSmoothingMode。

这里我很简单的借用前面的结论告诉你:

1.凡是你要用DrawXXXX或者FillXXXX画出来的,你要让他平滑,你就要用GdipSetSmoothingMode

2.其它的呢看它的类型,比如文字那么就是GdipSetTextRenderingHint……(言下之意就是还有其它的东西哦)

我们第三点总结Brush和Pen。

1.Pen是一只笔(- -||)。用于DrawXXXX的。描边。你可以通过一个纯色创建Pen(GdipCreatePen1),也可以通过一个Brush创建Pen:GdipCreatePen2(比如说纹理Pen,渐变Pen等等,不过貌似GDI+有点BUG)

2.Brush呢是刷子。我们有贴图刷子,预置纹理刷子,纯色刷子,渐变刷子,路径刷子等等。

(1)贴图刷:我们会在下一章深入探讨

(2)纯色刷:我们已经用过了,很简单——给一个颜色,传回一个Brush。

(3)渐变刷:我们也用过了,跟纯刷子差不多,给两个颜色就可以了,还有一个渐变方向~~,当然也是传回一个Brush

(4)路径刷:这个刷子很高级 可以实现前面的(2)和(3)的刷子以及他们不能实现的内容——我们可以按照路径让他去渐变……还有很多其它功能。这个嘛 以后有空我也会说的 呵呵

我们第四点总结路径。

路径我们虽然只借用到了文字路径,但是如果你翻一下我提供的API大杂烩会发现 关于Path有很多有趣的东西。例如有添加直线路径,添加圆弧路径,添加曲线路径,路径合并,路径旋转等等……很强大吧。

路径,我们需要给他一个初始化好的Path,然后按照各种需要给它参数;最后我们要把它画出来。

以后其它的路径东西我们有空会探讨。

最后再说下之前提过的一点:如果你发现复制了我的代码 结果东西没出来,那么请确保你的窗体的AutoRedraw=True。切记切记 不要忘记
本帖最后由 reker 于 2009-9-17 21:54 编辑

Visual Basic 6 GDI+ 入门教程[6] 图片

VB自己的绘图语句都需要用LoadPicture载入图片,同样,GDI+中也需要。

1.载入(初始化)图片资源

(1)来自文件:GdipLoadImageFromFile

我们先来看看这个最简单基本的载入图片来自文件(只能看 不能运行 呵呵):

Dim img As Long, img_W As Long, img_H As Long

GdipLoadImageFromFile StrPtr("C:\TestImage.png"), img
GdipGetImageWidth img, img_W
GdipGetImageHeight img, img_H
'GdipDisposeImage img
当然 这里面载入长宽是可选的。

最后呢 别忘记释放Image,否则内存突然没了可不要找我~

(2)来自资源文件:GdipLoadImageFromStream

这个函数主要是用来从资源文件(RES)载入图像的,怎么载入呢?我们来看函数,函数是从Stream载入,但是我们VB6没有集成Stream对象,从RES读取出来(LoadResData)也只是返回Byte()。不过很好,OLE提供了一个函数能够将Byte()变为一个IStream对象——我们需要这个API

Declare Sub CreateStreamOnHGlobal Lib "ole32.dll" (ByRef hGlobal As Any, ByVal fDeleteOnRelease As Long, ByRef ppstm As Any)
示例代码:

Dim img As Long
Dim ResData() As Byte, IStream As Object

ResData = LoadResData(101, "CUSTOM")
CreateStreamOnHGlobal ResData(0), False, IStream
GdipLoadImageFromStream IStream, img

Set IStream = Nothing
'GdipDisposeImage img
2.绘制图片

(1)GdipDrawImage(I) 【不推荐使用】

这是最普通的画法,不需要长宽设置 注意:它貌似不按原大小绘制!不推荐使用!。我们初始化GDI+省略……图片资源也省略(支持32位),来看这种GdipDrawImage(I)。(技巧:有I的记住了 坐标、长宽都是Long型 没有I的一般都是Single)

Dim img As Long

GdipLoadImageFromFile StrPtr("C:\TestImage.png"), img
'此处请初始化GDI+以及Graphics
GdipDrawImage Graphics, img, 0, 0
(2)GdipDrawImageRect(I)【推荐】

这是第二高级的画法,我们可以对图片的大小进行改变(拉伸)

Dim img As Long

GdipLoadImageFromFile StrPtr("C:\TestImage.png"), img
'此处请初始化GDI+以及Graphics
GdipDrawImageRect Graphics, img, 0, 0, 100, 200  '拉伸到100*200
(3)GdipDrawImageRectRect(I)

不要以为微软脑残了。这个可是很高级的画法。

首先通过它我们可以画一个图的一个部分 并且同样可以改变大小(好处:我们可以把所有的图片资源综合到一个图片中)

第二呢这个支持ImageAttribs图片“滤镜”:我们可以改变图片透明度和各种属性

接下来来看看这个的画法:

Dim img As Long

GdipLoadImageFromFile StrPtr("C:\TestImage.png"), img
'此处请初始化GDI+以及Graphics
GdipDrawImageRectRectI Graphics, img, 20, 20, 10, 10, 0, 0, 100, 200, UnitPixel
注意咯 第三~第六个参数是原来图片中要截取的部分;第七~第十呢则是画到哪里以及画出来多大的设置。

(4)贴图刷

贴图刷子 跟其它刷子一样 我们需要创建刷子 另外我们需要先初始化图片

来看代码:

Dim img As Long, textureBrush As Long

GdipLoadImageFromFile StrPtr("C:\TestImage.png"), img
'此处请初始化GDI+以及Graphics
GdipCreateTexture img, WrapModeTileFlipX, textureBrush
GdipFillRectangle Graphics, textureBrush, 0, 0, 100, 100
贴图刷子跟其它刷子有什么区别呢?普通画法(DrawImage)支持的是拉伸,贴图刷则是平铺。另外贴图刷还要注意定位问题。因为贴图刷纹理起始点是0,0。因此不代表从任何位置画都可以画到正好的图片。

贴个图,直观明了。



那么贴图刷子中如何调整图片起始位置呢?我们可以平移图片——GdipTranslateTextureTransform。参数很简单 是平移量。(注意:这个我记得是参照之前量的,不是原图片;因此更改平移量要先Reset下:GdipResetTextureTransform)
附件: 您所在的用户组无法下载或查看附件
本帖最后由 reker 于 2009-9-17 21:54 编辑

Visual Basic 6 GDI+ 入门教程[7] Graphics 其他内容

1.其他创建方式

我们之前创建Graphics都是从DC创建的,不过GDI+还有几种创建画布方法,且很重要哦

(1)hWnd(FromHWND)

如名,从句柄创建。本人不怎么用这个。

以下代码从窗体句柄创建Graphics

    'Dim Graphics As Long
    GdipCreateFromHWND Me.hWnd, Graphics
(2)Image/Bitmap(FromImage) [Important]

某些人用.Net发现.Net有神奇的从图片创建(Graphics.FromImage)的办法,这个办法主要用来保存为图片用。那么 FromImage的原型是什么呢?其实它的名字很囧:GdipGetImageGraphicsContext。它可以从Image创建 Graphics,当然从Bitmap也可以。

以下代码是从img创建Graphics

    'Dim img As Long, Graphics As Long
    'GdipLoadImageFromFile StrPtr("C:\1.png"), img
    GdipGetImageGraphicsContext Graphics, img
2.清除画布内容

对于有透明通道的绘制,每次绘制都必须擦除前面所画,否则会透明重叠……

办法1是自己FillRectangle一下,不过GDI+已经给我们更加直接的办法了:

以下代码用白色清除Graphics上内容

    'Dim Graphics As Long
    GdipGraphicsClear Graphics, &HFFFFFFFF
3.整体旋转

这个是整体的旋转,就是把画布旋转了……所以说~~如果只有一张图片那么旋转后图片边缘就是锯齿的(因为画布的边缘没有消除锯齿的功能)

以下代码将Graphics旋转20度

    'Dim Graphics As Long
    GdipRotateWorldTransform Graphics, 20, MatrixOrderApPend
4.整体平移

这个也是整体的,整体的平移一个量,是增量,相对量,不是绝对量。

以下代码将Graphics向右,向下平移10px,20px

    'Dim Graphics As Long
    GdipTranslateWorldTransform Graphics, 10, 20, MatrixOrderApPend
5.剪辑(遮掩层)

剪辑区域设置以后,绘制的内容就会仅限于这个区域内;超出的部分将被无视掉。但是原来的内容还在原来地方,不受剪辑区域影响。

以下代码设置一块剪辑区域,X=10 Y=20 Width=100 Height=100 ( (10,20) - (110,120) )

    'Dim Graphics As Long
    GdipSetClipRectI Graphics, 10, 20, 100, 100, CombineModeReplace
设置了当然还有取消——

    'Dim Graphics As Long
    'GdipSetClipRectI Graphics, 10, 20, 100, 100, CombineModeReplace
    GdipResetClip Graphics
本帖最后由 reker 于 2009-9-17 21:55 编辑

Visual Basic 6 GDI+ 入门教程[8] Bitmap魔法(1):创建

其实Bitmap和Image是很像的(位图、图片),事实上他们也可以互相转化,不过他们各有不同特点。Bitmap有很多神奇的魔法,内容比较多,加上开学了,我每次只能说小部分了~~

知识点少,所以代码我会比较充实一点 ..  (其实我很幸运,我们班其他人这会儿不能开电脑)

1.CreateBitmapFromFile

函数是GdipCreateBitmapFromFile。如名,这个函数是从文件载入一个Bitmap。既然bmp和img可以串用,所以说一定程度上这个和GdipLoadImageFromFile差不多。

当然,这两个函数的参数也的确也是几乎一样的。

注意:下例中,载入文件是C:\TestImg.png。

Option Explicit

Dim bitmap As Long, bmW As Long, bmH As Long
Dim Graphics As Long

Private Sub Form_Load()
    InitGdiplus
   
    '从文件载入Bitmap
    GdipCreateBitmapFromFile StrPtr("C:\TestImg.png"), bitmap
    GdipGetImageWidth bitmap, bmW
    GdipGetImageHeight bitmap, bmH
   
    '以下是用于绘制Bitmap的
    GdipCreateFromHDC Me.HDC, Graphics
    GdipDrawImageRectI Graphics, bitmap, 0, 0, bmW, bmH
   
    '扫地工作
    GdipDeleteGraphics Graphics
    GdipDisposeImage bitmap  'Bitmap没有释放函数,直接拿Image的来用。这是允许的,因为这样做返回0(OK)。
   
    TerminateGdiplus
End Sub
同样,不要忘记了,Form的AutoRedraw=True.

看到这里,可能有人要问了,以前我一直把Terminate之类的东西放到Form_Unload中,但是这次却放到了Load中,那么到底放在哪里呢?其实,具体放哪里要看实际情况。

首先,Terminate这些东西,是用于释放资源的。因此无论如何我们都要调用一下~。

然后在我们这个例子中,我们其实只绘制了一次,没有后续绘制的需求,因此可以完成任务以后就Terminate/Delete/Dispose掉。

而我前面的例子其实都可以这么做。不过你自己的程序不一定就是这样。

例如我们用GDI+边写一个钟。钟是一个不断重新绘制的过程,因此最后Unload时候释放为宜;而如果我们要用GDI+绘制一个不变的界面,那么一般可以绘制后就释放。不过一般来说因为界面不只一个,一个窗体的界面部分绘制完毕后可以释放相关资源,但是GDI+是不Shutdown的,因为我们还要给他其他窗体的绘制任务……

2.CreateBitmapFromStream

这个函数跟GdipLoadImageFromStream是差不多的。。

下例:载入图片从101号资源。

Option Explicit
Private Declare Sub CreateStreamOnHGlobal Lib "ole32.dll" (ByRef hGlobal As Any, ByVal fDeleteOnRelease As Long, ByRef ppstm As Any)

Dim img As Long, imgW As Long, imgH As Long, Graphics As Long

Private Sub Form_Load()
    InitGdiplus
   
    Dim ResData() As Byte, IStream As Object

    ResData = LoadResData(101, "CUSTOM")
    CreateStreamOnHGlobal ResData(0), False, IStream
    GdipCreateBitmapFromStream IStream, bitmap
    GdipGetImageWidth img, imgW
    GdipGetImageHeight img, imgH
   
    Set IStream = Nothing '不要忘记把他释放了
   
    GdipCreateFromHDC Me.HDC, Graphics
    GdipDrawImageRectI Graphics, img, 0, 0, imgW, imgH
   
    GdipDeleteGraphics Graphics
    GdipDisposeImage img
   
    TerminateGdiplus
End Sub
3.CreateBitmapFromHBITMAP

这里的HBITMAP就是我们的PictureBox/Form等等的Picture.Handle中获取。具体作用是什么呢?例如,GDI与GDI+的图片的转换。

一般来说,GdipCreateBitmapFromHBITMAP的第二个参数为0.

Option Explicit

Dim bitmap As Long, bmW As Long, bmH As Long, Graphics As Long

Private Sub Form_Load()
    InitGdiplus
   
    GdipCreateBitmapFromHBITMAP Picture1.Picture.Handle, 0, bitmap
    GdipGetImageWidth bitmap, bmW
    GdipGetImageHeight bitmap, bmH
   
    GdipCreateFromHDC Me.HDC, Graphics
    GdipDrawImageRectI Graphics, bitmap, 0, 0, bmW, bmH
   
    GdipDeleteGraphics Graphics
    GdipDisposeImage bitmap
   
    TerminateGdiplus
End Sub
4.CreateBitmapFromHICON

VB6中用这个呢,主要是为了获取窗体等等的ICON。注意了,虽然看上去VB中Icon属性和Picture属性貌似是一个东西其实不然。因此读取Icon必须要这么读,不能用上面方法。

Option Explicit

Dim bitmap As Long, bmW As Long, bmH As Long, Graphics As Long

Private Sub Form_Load()
    InitGdiplus
   
    GdipCreateBitmapFromHICON Me.Icon.Handle, bitmap
    GdipGetImageWidth bitmap, bmW
    GdipGetImageHeight bitmap, bmH
   
    GdipCreateFromHDC Me.HDC, Graphics
    GdipDrawImageRectI Graphics, bitmap, 0, 0, bmW, bmH
   
    GdipDeleteGraphics Graphics
    GdipDisposeImage bitmap
   
    TerminateGdiplus
End Sub
5.CreateBitmapFromGraphics

这个是从一个现存的Graphics创建位图。这个和GdipGetImageGraphicsContext不一样,GdipGetImageGraphicsContext创建出来的Graphics修改后会影响原来的Image(绑定),而这个GdipCreateBitmapFromGraphics就不会,完全是创建一个副本。

Declare Function GdipCreateBitmapFromGraphics Lib "Gdiplus" (ByVal Width As Long, ByVal Height As Long, ByVal Graphics As Long, bitmap As Long) As GpStatus
参数说明:

Width,Height:新创建的位图的长、宽

graphics:从哪个Graphic创建Bitmap

bitmap:创建出来的Bitmap指针放到哪里

Option Explicit

Dim bitmap As Long, Graphics As Long

Private Sub Form_Load()
    InitGdiplus
   
    GdipCreateFromHDC Me.HDC, Graphics
    GdipGraphicsClear Graphics, &HFFFF0000  '为了显示点内容
   
    GdipCreateBitmapFromGraphics 100, 100, Graphics, bitmap  '创建一个现存的副本
   
    GdipDrawImageRectI Graphics, bitmap, 0, 0, 100, 100  '绘制这个副本
   
    GdipDeleteGraphics Graphics
    GdipDisposeImage bitmap
   
    TerminateGdiplus
End Sub

6.CreateBitmapFromScan0 [Important]

说了那么多,我们可以发现,貌似所有的CreateBitmap都要有一个现存的蓝本……那么如何凭空创建一个Bitmap呢(其实是从内存)?就是这个函数了!

Declare Function GdipCreateBitmapFromScan0 Lib "Gdiplus" (ByVal Width As Long, ByVal Height As Long, ByVal stride As Long, ByVal PixelFormat As Long, scan0 As Any, bitmap As Long) As GpStatus
参数说明:

Width,Height:新位图的长、宽

strid:此为指定一个ID。一般是0

PixelFormat:设定这个Bitmap的色深,我比较喜欢GpPixelFormat.PixelFormat32bppARGB。

scan0:指定内存地址……ByVal 0就是从内存新创建一个

bitmap:传回的位图指针

Option Explicit

Dim bitmap As Long, Graphics As Long, gBmp As Long

Private Sub Form_Load()
    InitGdiplus
   
    GdipCreateBitmapFromScan0 100, 100, 0, GpPixelFormat.PixelFormat32bppARGB, ByVal 0, bitmap
    GdipGetImageGraphicsContext bitmap, gBmp
    GdipGraphicsClear gBmp, &HFFFF0000
   
    GdipCreateFromHDC Me.HDC, Graphics

    GdipDrawImageRectI Graphics, bitmap, 0, 0, 100, 100
   
    GdipDeleteGraphics gBmp
    GdipDeleteGraphics Graphics
    GdipDisposeImage bitmap
   
    TerminateGdiplus
End Sub

现在基本上所有常用的创建Bitmap方式都结束了。好累啊。。。
辛苦了,支持~~~
返回列表