65.9K
CodeProject 正在变化。 阅读更多。
Home

开始使用 GDI+

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.80/5 (64投票s)

2001年5月13日

5分钟阅读

viewsIcon

2051539

downloadIcon

12163

开始使用新的 Microsoft 图形库。

Sample Image - StartingGDIPlus.jpg

引言

我使用GDI+大约一周了,我必须说这是一个值得欢迎的升级。我正在开发一个绘画程序,很多我以为需要自己编写的功能现在都内置了,意味着我可以“免费”获得它们。优点和缺点,我想,是相同的——我希望我的程序能做到的事情现在更容易实现了,这对我自己以及任何想写类似东西的人都更容易。

在开始之前,我想感谢所有通过告诉我GDI+的存在以及在哪里获取它而帮助我入门的人。这里的部分信息是直接摘自CodeProject 论坛上讨论这些事宜的帖子。当然,所有酷炫的功能都是我写的:0)

首先,你需要安装GDI+才能使用它。它包含在2001年2月的Microsoft Platform SDK中。如果你不下载SDK(或者没有拿到CD),那真是太糟糕了。SDK的每一次发布都包含一些很棒的新功能,例如WTL的更新。总之,如果你去 ftp.microsoft.com 下载它,我会原谅你。如果你只需要GDI+,相关文件在psdk-common.11.cab中(至少我被告知是这样,我下载了整个SDK)。

你需要的文件是:

  • DLL:gdiplus.dll
  • 库:gdiplus.lib
  • 头文件:gdiplus*.h
  • 帮助文件:gdicpp.chm & gdicpp.chi

别忘了确保将Visual C++设置为指向包含目录中的.h文件,以及链接目录中的.lib文件。还要通过选择“项目/设置/链接”并将gdiplus.lib添加到对象/库模块区域来将其包含在你的库列表中。要设置包含和库目录,请转到“工具/选项/目录”。

要让你的应用程序与GDI+一起工作,请执行以下操作:

  • stdafx.h中,添加:
    #include <gdiplus.h>
    (在底部,在#endif之前)
  • 在你的应用程序类中,添加成员:
    ULONG_PTR m_gdiplusToken;
    ULONG_PTRunsigned __int64的一个typedef。我通常不喜欢使用typedef,但在这种情况下我将破例...
  • InitInstance中,添加:
    // Initialize GDI+
    Gdiplus::GdiplusStartupInput gdiplusStartupInput;
    Gdiplus::GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);

    我很想告诉你这一切是如何工作的,但我恐怕微软目前还没有提供源代码,只有头文件和DLL。
     

  • ExitInstance中,添加:
    Gdiplus::GdiplusShutdown(m_gdiplusToken);

我在此提到,你可以选择在所有命令前加上GdiPlus::,或者你也可以简单地在代码的开头添加:

using namespace GdiPlus; 

我的其余示例将假定你已经首先包含了此命令,并且不会像这样添加命令前缀。所以现在我们有一个初始化GDI+的程序,这可能是讨论GDI+实际工作原理的一个好地方。正如你可能知道的,GDI的工作概念是设备上下文。通常,你会像这样使用GDI绘制一个矩形:

(在你的OnPaint处理函数中)

CPaintDC dc(this); // Creates a device context for the client area, which
                   // also erases the area to be drawn.

CPen MyPen, * pOldPen;
CBrush MyBrush, * pOldBrush;




// A red pen, one pixel wide MyPen.Create(1, PS_SOLID, RGB(255,0,0)); // Selecting an object returns the old one // we need to catch and return it to avoid memory leaks pOldPen = dc.SelectObject(&MyPen); // A Blue brush MyBrush.CreateSolidBrush(RGB(0, 0, 255)); pOldBrush = dc.SelectObject(&MyBrush); // Finally, we have our device context set up with our pen and brush and can // use them to draw.


//Draws a rectangle that is red on the outside, filled in blue dc.Rectangle(0, 0, 200, 200); dc.SelectObject(pOldPen); dc.SelectObject(pOldBrush);

需要理解的主要一点是,我选择一个画笔或刷子,它将一直保留在那里,直到我选择另一个,并且内存泄露的机会很多,而且不容易调试。相比之下,GDI+模型围绕着创建一个图形对象,如下所示:

CPaintDC dc(this);
Graphics graphics(dc.hdc); 
现在,这个对象将持有我们的DC,直到我们销毁或释放它,然后我们使用这个对象来操作我们的设备上下文。所有函数都接受它们使用的画笔或刷子,这意味着不会有内存泄露,并且更容易编写可以绘制多种颜色的代码。在提供示例之前,让我指出GDI+的另一个令人兴奋之处。在GDI中,我们使用COLORREF作为存储颜色的变量。它是DWORD的typedef,并且使用RGB宏构建COLORREF。可以使用GetRValueGetGValueGetBValue来检索颜色。相比之下,GDI+使用COLOR类,它接受四个值来构造——额外的一个是alpha。如果你不熟悉alpha透明度的概念,想象一下你正在透过彩色玻璃窗看东西。玻璃的颜色会影响你看到的后面的景象,但它们会遮挡你视线的程度取决于玻璃的厚度。Alpha透明度同样会将你用来绘制的颜色与下面的画布颜色混合。GDI+中的颜色是ARGB,alpha值首先指定。所以要绘制一条线,我们可以这样做:
Pen MyPen(Color(255, 0, 255, ));  // A green pen, with full alpha
graphics.DrawLine(&pen, 0, 0, 200, 100);

GDI+还废除了当前位置的概念:在GDI中,我们使用MoveTo(point),然后是LineTo(point)。现在我们一次性指定两个点。

我提供了一个示例程序,旨在通过提供必要的框架来方便实验,让你能够玩弄代码,并且如果你以前没有见过alpha,还可以运行它来查看alpha是如何工作的。绘图代码创建了一个红色和蓝色的图案,然后用绿色、然后是洋红色绘制,并且alpha值首先从上到下,然后从左到右进行淡化。

示例程序的OnPaint方法如下所示:

using namespace Gdiplus;

CPaintDC dc(this);

Graphics graphics(dc.m_hDC);

// Pen can also be constructed using a brush or another
//pen. There is a second parameter - a width which defaults to 1.0f
Pen blue (Color(255, 0, 0, 255));

Pen red (Color(255, 255, 0, 0));
int y = 256;
for (int x = 0; x < 256; x += 5)
{
	graphics.DrawLine(&blue, 0, y, x, 0);
	graphics.DrawLine(&red, 256, x, y, 256);  
	y -= 5;
}		
for (y = 0; y < 256; y++)
{
	Pen pen(Color(y, 0, 255,0));
	// A green pen with shifting alpha 
	graphics.DrawLine(&pen, 0, y, 256, y); 
	// The sleep is to slow it down so you can watch the effect 
	Sleep(20);
}		
for (x = 0; x  < 256;  x++)
{
	Pen pen(Color(x, 255, 0, 255));
	// A green pen with shifting alpha 
	graphics.DrawLine(&pen, x, 100, x, 200);
	// The sleep is to slow it down so you can watch the effect
	Sleep(20); 
}

这标志着我的第一个GDI+教程的结束。我的目标只是让你上手——向你展示如何设置一个程序来使用GDI+,并解释一些关于它设置方式的基本概念。我的下一个教程将是关于使用画笔——使用GDI+,你可以制作一个显示渐变的画笔,或者用位图来纹理化。敬请期待——真正的精彩即将开始……

© . All rights reserved.