BEGIN_MESSAGE_MAP(CGdiexampleDlg, CDialog) //{{AFX_MSG_MAP(CGdiexampleDlg) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_COMMAND(IDM_GDI_DRAW_LINE, OnGdiDrawLine) ON_COMMAND(IDM_GDIP_DRAW_LINE, OnGdipDrawLine) ON_COMMAND(IDM_Gradient_Brush, OnGradientBrush) ON_COMMAND(IDM_Cardinal_Spline, OnCardinalSpline) ON_COMMAND(IDM_Transformation_Matrix, OnTransformationMatrix) ON_COMMAND(IDM_Scalable_Region, OnScalableRegion) ON_COMMAND(IDM_IMAGE, OnImage) ON_COMMAND(IDM_Alpha_Blend, OnAlphaBlend) ON_COMMAND(IDM_TEXT, OnText) //}}AFX_MSG_MAP END_MESSAGE_MAP() |
3.GDI编程
"GDI"菜单下的"画线"子菜单单击事件消息处理函数的代码如下:
void CGdiexampleDlg::OnGdiDrawLine() { // TODO: Add your command handler code here CClientDC dc(this); //逻辑坐标与设备坐标变换 CRect rect; GetClientRect(&rect); dc.SetMapMode(MM_ANISOTROPIC); dc.SetWindowOrg(0, 0); dc.SetWindowExt(rect.right, rect.bottom); dc.SetViewportOrg(0, rect.bottom / 2); dc.SetViewportExt(rect.right, - rect.bottom); //创建绘制正旋曲线的pen并将其选入设备上下文 CPen pen(PS_SOLID, 1, RGB(255, 0, 0)); HGDIOBJ oldObject = dc.SelectObject(pen.GetSafeHandle()); //绘制正旋曲线 dc.MoveTo(0, 0); for (int i = 0; i < rect.right; i++) { dc.LineTo(i, 100 *sin(2 *(i / (rect.right / 5.0)) *PI)); } //创建绘制x轴的pen并将其选入设备上下文 CPen penx(PS_SOLID, 1, RGB(0, 0, 255)); dc.SelectObject(penx.GetSafeHandle()); //绘制X轴 dc.MoveTo(0, 0); dc.LineTo(rect.right, 0); //恢复原先的pen dc.SelectObject(oldObject); } |
公式中的
因此,经过程序中的dc.SetWindowOrg (0,0) 和dc.SetViewportOrg (0,rect.bottom/2)语句我们设置了视口和窗口的原点;而经过程序中的dc.SetWindowExt (rect.right,rect.bottom) 和dc.SetViewportExt (rect.right,-rect.bottom) 语句我们设置了视口和窗口的范围。由于视口和窗口的纵坐标方向相反,设置视口的垂直范围为负值。这样我们得到了一个逻辑坐标原点为客户区水平方向最左边和垂直方向居中的坐标系,我们在这个坐标系上直接绘制正旋曲线,不需要再理睬Windows对话框客户区坐标了。
void CGdiexampleDlg::OnGdiDrawLine()函数中未指定逻辑设备和物理设备的映射模式,则为缺省的MM_TEXT。在这种模式下,一个逻辑单位对应于一个像素点。映射模式是GDI中的一个重要概念,其它的映射模式还有MM_LOENGLlSH、MM_HIENGLISH、MM_LOMETRIC和MM_HIMETRIC等。我们可以通过如下语句指定映射模式为MM_TEXT:
dc.SetMapMode(MM_TEXT); |
void CGdiexampleDlg::OnGdipDrawLine() { // TODO: Add your command handler code here CClientDC dc(this); //逻辑坐标与设备坐标变换 CRect rect; GetClientRect(&rect); dc.SetMapMode(MM_ANISOTROPIC); dc.SetWindowOrg(0, 0); dc.SetWindowExt(rect.right, rect.bottom); dc.SetViewportOrg(0, rect.bottom / 2); dc.SetViewportExt(rect.right, - rect.bottom); //创建Graphics对象 Graphics graphics(dc); //创建pen Pen myPen(Color::Red); myPen.SetWidth(1); //画正旋曲线 for (int i = 0; i < rect.right; i++) { graphics.DrawLine(&myPen, i, 100 *sin(2 *(i / (rect.right / 5.0)) *PI), i + 1, 100 *sin(2 *((i + 1) / (rect.right / 5.0)) *PI)); } //画X轴 myPen.SetColor(Color::Blue); graphics.DrawLine(&myPen, 0, 0, rect.right, 0); } |
#define UNICODE #ifndef ULONG_PTR #define ULONG_PTR unsigned long* #endif #include "c:/gdiplus/includes/gdiplus.h" using namespace Gdiplus; #pragma comment(lib, "c:/gdiplus/lib/gdiplus.lib") |
/////////////////////////////////////// Call this when linking to MFC statically |
渐变的画刷
GDI+提供了用于填充图形、路径和区域的线性渐变画刷和路径渐变画刷。
线性渐变画刷使用渐变颜色来填充图形。
当用路径渐变画刷填充图形时,可指定从图形的一部分移至另一部分时画刷颜色的变化方式。例如,我们可以只指定图形的中心颜色和边缘颜色,当画刷从图形中间向外边缘移动时,画刷会逐渐从中心颜色变化到边缘颜色。
void CGdiexampleDlg::OnGradientBrush() { // TODO: Add your command handler code here CClientDC dc(this); CRect rect; GetClientRect(&rect); //创建Graphics对象 Graphics graphics(dc); //创建渐变画刷 LinearGradientBrush lgb(Point(0, 0), Point(rect.right, rect.bottom), Color::Blue, Color::Green); //填充 graphics.FillRectangle(&lgb, 0, 0, rect.right, rect.bottom); } |
void CGdiexampleDlg::OnCardinalSpline() { // TODO: Add your command handler code here CClientDC dc(this); //创建Graphics对象 Graphics graphics(dc); Point points[] = { Point(0, 0), Point(100, 200), Point(200, 0), Point(300, 200), Point(400, 00) }; //直接画线 for (int i = 0; i < 4; i++) { graphics.DrawLine(&Pen(Color::Blue, 3), points[i], points[i + 1]); } //利用基数样条画线 graphics.DrawCurve(&Pen(Color::Red, 3), points, 5); } |
持久的路径对象
图5演示了正方形经过旋转和拉伸之后的效果:黑色的为原始图形,红色的为旋转45度之后的图形,蓝色的为经过拉伸为平行四边形后的图形。 可伸缩区域 GDI+通过对区域(Region)的支持极大地扩展了GDI。在GDI 中,区域存储在设备坐标中,可应用于区域的唯一变形是平移。但是在GDI +中,区域存储在全局坐标(世界坐标)中,可对区域利用变形矩阵进行变形(旋转、平移、缩放等)。
上述程序中以蓝色填充一个三角形区域,接着将此区域旋转和拉伸,再次显示,其效果如图6。 |
丰富的图像格式支持
GDI +提供了Image、Bitmap 和Metafile 类,方便用户进行图像格式的加载、操作和保存。GDI+支持的图像格式有BMP、GIF、JPEG、EXIF、PNG、TIFF、ICON、WMF、EMF等,几乎涵盖了所有的常用图像格式。
void CGdiexampleDlg::OnImage() { // TODO: Add your command handler code here CClientDC dc(this); //创建Graphics对象 Graphics graphics(dc); Image image(L "d:/1.jpg"); //在矩形区域内显示jpg图像 Point destPoints1[3] = { Point(10, 10), Point(220, 10), Point(10, 290) }; graphics.DrawImage(&image, destPoints1, 3); //在平行四边形区域内显示jpg图像 Point destPoints2[3] = { Point(230, 10), Point(440, 10), Point(270, 290) }; graphics.DrawImage(&image, destPoints2, 3); } |
Alpha混合
Alpha允许将两个物体混合起来显示,在3D气氛和场景渲染等方面有广泛应用。它能"雾化"图像,使得一个图像着色在另一个半透明的图像上,呈现一种朦胧美。我们知道,一个像素可用R,G,B三个维度来表示,我们可以再加上第4个即:Alpha维度(channel),表征透明程度。
void CGdiexampleDlg::OnAlphaBlend() { // TODO: Add your command handler code here CClientDC dc(this); //创建Graphics对象 Graphics graphics(dc); //创建ColorMatrix ColorMatrix ClrMatrix = { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f }; //将ColorMatrix赋给ImageAttributes ImageAttributes ImgAttr; ImgAttr.SetColorMatrix(&ClrMatrix, ColorMatrixFlagsDefault,ColorAdjustTypeBitmap); //在矩形区域内显示jpg图像 Image img1(L "d:/1.jpg"); Point destPoints1[3] = { Point(10, 10), Point(220, 10), Point(10, 290) }; graphics.DrawImage(&img1, destPoints1, 3); //Alpha混合 Image img2(L "d:/2.jpg"); int width, height; width = img2.GetWidth(); height = img2.GetHeight(); graphics.DrawImage(&img2, RectF(10, 10, 210, 280), 0, 0, width, height,UnitPixel, &ImgAttr); //在平行四边形区域内显示jpg图像 Point destPoints2[3] = { Point(230, 10), Point(440, 10), Point(270, 290) }; graphics.DrawImage(&img1, destPoints2, 3); //Alpha混合 graphics.DrawImage(&img2, destPoints2, 3, 0, 0, width, height, UnitPixel,&ImgAttr); } |
强大的文字输出
GDI+拥有极其强大的文字输出处理能力,输出文字的颜色、字体、填充方式都可以直接作为Graphics类DrawString成员函数的参数进行设置,其功能远胜过GDI设备上下文的TextOut函数。
void CGdiexampleDlg::OnText() { // TODO: Add your command handler code here CClientDC dc(this); //创建Graphics对象 Graphics graphics(dc); //创建20号"楷体"字体 FontFamily fontFamily1(L "楷体_GB2312"); // 定义"楷体"字样 Font font1(&fontFamily1, 20, FontStyleRegular, UnitPoint); //定义输出UNICODE字符串 WCHAR string[256]; wcscpy(string, L "天极网的读者朋友,您好!"); //以蓝色画刷和20号"楷体"显示字符串 graphics.DrawString(string, (INT)wcslen(string), &font1, PointF(30, 10),&SolidBrush(Color::Blue)); //定义字符串显示画刷 LinearGradientBrush linGrBrush(Point(30, 50), Point(100, 50), Color(255, 255,0, 0), Color(255, 0, 0, 255)); //以线性渐变画刷和创建的20号"楷体"显示字符串 graphics.DrawString(string, (INT)wcslen(string), &font1, PointF(30, 50),&linGrBrush); //创建20号"华文行楷"字体 FontFamily fontFamily2(L "华文行楷"); // 定义"楷体"字样 Font font2(&fontFamily2, 20, FontStyleRegular, UnitPoint); //以线性渐变画刷和20号"华文行楷"显示字符串 graphics.DrawString(string, (INT)wcslen(string), &font2, PointF(30, 90),&linGrBrush); //以图像创建画刷 Image image(L "d:/3.jpg"); TextureBrush tBrush(&image); //以图像画刷和20号"华文行楷"显示字符串 graphics.DrawString(string, (INT)wcslen(string), &font2, PointF(30, 130),&tBrush); //创建25号"华文中宋"字体 FontFamily fontFamily3(L "华文中宋"); // 定义"楷体"字样 Font font3(&fontFamily2, 25, FontStyleRegular, UnitPoint); //以图像画刷和20号"华文行楷"显示字符串 graphics.DrawString(string, (INT)wcslen(string), &font3, PointF(30, 170),&tBrush); } |