使用GDI的一些实例

(1)利用绘图函数创建填充区。共有三个填充图形,第一个是用深灰色画刷填充带圆角的矩形,第二个是采用亮灰色画刷填充一个椭圆型图,第三个是用虚画刷填充饼形图。
Tips:使用虚画刷填充时,看不出填充效果!!!

#include<windows.h>
#include<stdlib.h>
#include<string.h>
long WINAPI WndProc(
HWND hWnd,
UINT iMessage,
UINT wParam,
LONG lParam);

BOOL InitWindowsClass(HINSTANCE hInstance);
BOOL InitWindows(HINSTANCE hInstance,int nCmdShow);

int WINAPI WinMain     //主函数
( HINSTANCE hInstance,
   HINSTANCE hPrevInstance,
   LPSTR lpCmdLine,
   int nCmdShow)
{
MSG Message;
if(!InitWindowsClass(hInstance))
   return FALSE;
if(!InitWindows(hInstance,nCmdShow))
   return FALSE;
while(GetMessage(&Message,0,0,0)) //消息循环
{
   TranslateMessage(&Message);
   DispatchMessage(&Message);
}
return Message.wParam;
}

long WINAPI WndProc(HWND hWnd,
                    UINT iMessage,
                    UINT wParam,
                    LONG lParam)
{
HDC hDC;               //定义指向设备的句柄
HBRUSH hBrush;         //定义指向画刷的句柄
HPEN hPen;             //定义指向画笔的句柄
PAINTSTRUCT PtStr;     //定义指向包含绘图信息的结构体变量
switch(iMessage)       //处理消息
{
case WM_PAINT:        //处理绘图消息
   hDC=BeginPaint(hWnd,&PtStr);
   SetMapMode(hDC,MM_ANISOTROPIC);         //设置映像模式
   hPen=(HPEN)GetStockObject(BLACK_PEN); //黑色画笔
   hBrush=(HBRUSH)GetStockObject(DKGRAY_BRUSH); //画刷
   SelectObject(hDC,hBrush);     //选择画刷
   SelectObject(hDC,hPen);       //选择画笔
   RoundRect(hDC,50,120,100,200,15,15); //绘制圆角矩形
   hBrush=(HBRUSH)GetStockObject(LTGRAY_BRUSH); //采用亮灰色画刷
   SelectObject(hDC,hBrush);     //选择画刷
   Ellipse(hDC,150,50,200,150);     //绘制椭圆
   hBrush=(HBRUSH)GetStockObject(HOLLOW_BRUSH); //虚画刷
   SelectObject(hDC,hBrush);    //选择画刷
   Pie(hDC,250,50,300,100,250,50,300,50); //绘制饼形
   EndPaint(hWnd,&PtStr); //结束绘图
   return 0;
case WM_DESTROY:      //结束应用程序
   PostQuitMessage(0);    return 0;
default:      //其他消息处理程序
   return(DefWindowProc(hWnd,iMessage,wParam,lParam)) ;
}
}

BOOL InitWindows(HINSTANCE hInstance,int nCmdShow)//初始化窗口
{
HWND hWnd;
hWnd=CreateWindow("WinFill", //生成窗口
     "填充示例程序",
     WS_OVERLAPPEDWINDOW,
     CW_USEDEFAULT,
     0,
     CW_USEDEFAULT,
     0,
     NULL,
     NULL,
     hInstance,
     NULL);
if(!hWnd)
   return FALSE;
ShowWindow(hWnd,nCmdShow); //显示窗口
UpdateWindow(hWnd);
return TRUE;
}

BOOL InitWindowsClass(HINSTANCE hInstance) //定义窗口类
{
WNDCLASS WndClass;
WndClass.cbClsExtra=0;
WndClass.cbWndExtra=0;
WndClass.hbrBackground=(HBRUSH)(GetStockObject(WHITE_BRUSH));
WndClass.hCursor=LoadCursor(NULL,IDC_ARROW);
WndClass.hIcon=LoadIcon(NULL,"END");
WndClass.hInstance=hInstance;
WndClass.lpfnWndProc=WndProc;
WndClass.lpszClassName="WinFill";
WndClass.lpszMenuName=NULL;
WndClass.style=CS_HREDRAW|CS_VREDRAW;
return RegisterClass(&WndClass);
}

(2)应用画笔和画刷等工具绘制如图所示的图形


#include<windows.h>
#include<stdlib.h>
#include<string.h>
long WINAPI WndProc(HWND hWnd,UINT iMessage,UINT wParam,LONG lParam);
BOOL InitWindowsClass(HINSTANCE hInstance);
BOOL InitWindows(HINSTANCE hInstance,int nCmdShow);
//主函数
int WINAPI WinMain(HINSTANCE hInstance,
                   HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
{ MSG Message;
if(!InitWindowsClass(hInstance))
   return FALSE;
if(!InitWindows(hInstance,nCmdShow))
   return FALSE;
while(GetMessage(&Message,0,0,0))   //消息循环
{
   TranslateMessage(&Message);
   DispatchMessage(&Message);
}
return Message.wParam;
}
long WINAPI WndProc(HWND hWnd,UINT iMessage,UINT wParam,LONG lParam)
{
HDC hDC;       //定义设备环境句柄
HBRUSH hBrush;    //定义画刷的句柄
HPEN hPen;    //定义画笔的句柄
PAINTSTRUCT PtStr;    //定义指向包含绘图信息的结构体变量
//定义一个POINT数组,包括6个点
POINT points[6]={{100,212},{70,227},{70,250},{130,250},{130,227},{100,212}};
switch(iMessage)    //处理消息
{
case WM_PAINT:       //处理绘图消息
   hDC=BeginPaint(hWnd,&PtStr);
   hPen=(HPEN)GetStockObject(NULL_PEN); //获取系统定义的空画笔
   SelectObject(hDC,hPen);    //选择画笔
   hBrush=(HBRUSH)GetStockObject(BLACK_BRUSH); //获取系统定义的画刷
   SelectObject(hDC,hBrush); //选择画刷
   LineTo(hDC,50,50);    //画线
   DeleteObject(hPen);    //删除画笔
   hPen=CreatePen(PS_SOLID,2,RGB(255,0,0)); //创建画笔
   SelectObject(hDC,hPen); //选择画笔
   //画一个三角形
   LineTo(hDC,150,50);
   LineTo(hDC,100,137);
   LineTo(hDC,50,50);
   Polyline(hDC,points,6);      //画一个五边形
   Arc(hDC,63,137,138,212,100,137,100,137); //画一个圆
   Pie(hDC,213,137,288,212,240,137,260,137); //画一个圆饼
   Rectangle(hDC,213,212,287,250);           //画一个长方形
   RoundRect(hDC,213,100,287,137,20,20); //画一个圆角长方形
   DeleteObject(hPen);    //删除画笔
   DeleteObject(hBrush); //删除画刷
   EndPaint(hWnd,&PtStr); //结束绘图
   return 0;
case WM_DESTROY: //结束应用程序
   PostQuitMessage(0);
   return 0;
default://其他消息处理程序
return(DefWindowProc(hWnd,iMessage,wParam,lParam)) ;
    }
}
InitWindows与InitWindowsClass与上例相同,不再重复。

(3)设置映射与使用映射模式。程序的初始阶段按模式MM_TEXT绘图,用户单击鼠标以改变映射模式,单击左键,产生WM_LBUTTONDOWN消息,通知应用程序设置映射模式为ISOTROPIC,并调用InvalidateRect函数刷新用户区,在用户单击鼠标右键时,产生WM_RBUTTONDOWN消息,应用程序将映射模式设置成ANSIOTROPIC,同时刷新用户区。

LRESULT CALLBACK WndProc(…,…,…,…)
{
HDC hdc;
PAINTSTRUCT ps;
HBRUSH hB1,hB2;
switch(message)
{
case WM_LBUTTONDOWN:   //单击鼠标左键的消息
   nMode=MM_ISOTROPIC; //更改映射模式为MM_ISOTROPIC
   InvalidateRect(hwnd,NULL,1);   //刷新用户区
   break;
case WM_RBUTTONDOWN:   //单击鼠标右键消息
   nMode=MM_ANISOTROPIC; //更改显示模式为MM_ANISOTROPIC
   InvalidateRect(hwnd,NULL,1);   //刷新用户区
   break;
case WM_PAINT:
   hdc=BeginPaint(hwnd,&ps); //取得设备环境句柄
   SetMapMode(hdc,nMode); //设置映射模式
   SetWindowExtEx(hdc,150,150,NULL); //设置窗口区域
   SetViewportExtEx(hdc,150,100,NULL); //设置视口区域
   SetViewportOrgEx(hdc,150,60,NULL); //设置视口原点
   hB1=(HBRUSH)GetStockObject(WHITE_BRUSH); //定义白色画刷
   SelectObject(hdc,hB1);   //将黑白刷选入设备环境
   RoundRect(hdc,0,0,150,150,30,30); //绘制圆角矩形并填充
   hB2=(HBRUSH)GetStockObject(BLACK_BRUSH); //定义黑色画刷
   SelectObject(hdc,hB2);   //更改当前画刷为黑色画刷
   Ellipse(hdc,0,10,150,140);    //绘制椭圆并填充
   EndPaint(hwnd,&ps);     //释放设备环境句柄
   DeleteObject(hB1);     //删除画刷句柄
   DeleteObject(hB2);
   break;
case WM_DESTROY:
   PostQuitMessage(0);    break;  
default:
   return DefWindowProc(hwnd,message,wParam,lParam);
   }
return 0;
}

(4)编写一个程序,在屏幕上出现一个圆心沿正弦曲线轨迹移动的实心圆,而且,每隔四分之一周期,圆的填充色和圆的周边颜色都发生变化,同时,圆的半径在四分之一周期之内由正弦曲线幅值的0.2倍至0.6倍线性增长。

*** 正弦曲线是此题的基础。在WndMain()函数消息循环前,生成正弦曲线各点的坐标。把正弦曲线一个周期的横坐标分成100

个等分点,存储在数组lpSin[100]中,100个点的坐标计算如下:
for(int j=0;j<100;j++) //生成正弦曲线的点坐标
{
lpSin[j].x=(long)(j*2*Pi/100*60);
lpSin[j].y=(long)(dfRange*sin(j*2*Pi/100));
}

*** 动态显示圆在正弦曲线上移动
数组lpSin[100]的长度为100--->设定圆在正弦曲线移动时共有100个位置--->数组中每一个值是圆移动时圆心的坐标--->每四

分之一周期有25个位置,所以:
i<=25   处于第1个1/4周期,创建红色画笔和画刷;
25<i<50   处于第2个1/4周期,创建绿色画笔和画刷;
50<i<75   处于第3个1/4周期,创建蓝色画笔和画刷;
75<i<100 处于第4个1/4周期,创建黄色画笔和画刷;

**在消息WM_PAINT处理程序中,调用函数BeginPaint()获得设备环境句柄。由此经过线性差分计算圆半径的大小lRadious,第1

个1/4周期的程序代码如下:
if(i<=25)     //第一个1/4周期
{
hPen=CreatePen(PS_DASH,1,RGB(255,0,0));
hBrush=CreateHatchBrush(HS_BDIAGONAL,RGB(255,0,0));
lRadious=(long)(dfRange*0.2+i%25*dfRange*0.4/25);//计算半径
}

**创建的画笔和画刷选入设备环境后,调用函数Ellipse(…)绘制圆形下面这段代码是动态显示的关键:
Sleep(100);   //停0.1秒
if(i<100)   //i<100时调用函数刷新用户区发送WM_PAINT消息
//刷新用户区
   InvalidateRect(hWnd, //消息发到的窗口的句柄
     NULL, //代表刷新整个用户区
     1); //代表清除用户区中所有的显示内容

调用Sleep(100)函数使程序暂停0.1秒。所含参数100代表暂停的时间,使用毫秒作单位。

完整代码如下:
#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#define Pi 3.1415926

long WINAPI WndProc(HWND hWnd,UINT iMessage,UINT wParam,LONG lParam);
double dfTheta=0,dfRange=100.0;   //正弦曲线的角度变量.
long i=0,j=0;
long lCentreX=0,lCentreY=0,lRadious=(long)(0.2*dfRange);//定义圆心坐标和圆半径.
POINT lpSin[100]; //定义正弦曲线的点坐标.

int WINAPI WinMain(…,…,…,...)
{ …… // 填写窗口类属性
if(!RegisterClass(&WndClass))    //注册窗口.
{
   MessageBeep(0);
   return FALSE;
}
hWnd=CreateWindow("SIN", //窗口类名.
“4_4",     //标题名.
WS_OVERLAPPEDWINDOW,   //带标题栏,最大/小按钮的窗口
CW_USEDEFAULT,    //窗口左上角坐标.
0,      
CW_USEDEFAULT,    //采用缺省的宽度和高度.
0,
NULL,    //无父窗口.
NULL,    //无主菜单.
hInstance,    //当前实例句柄.
NULL);.

ShowWindow(hWnd,nCmdShow); //显示窗口.
UpdateWindow(hWnd);   //更新并绘制用户区
for(int j=0;j<100;j++)   //生成正弦曲线的点坐标.
{
   lpSin[j].x=(long)(j*2*Pi/100*60);
   lpSin[j].y=(long)(dfRange*sin(j*2*Pi/100));
}

while(GetMessage(&Message,0,0,0))
{
   TranslateMessage(&Message); //消息循环.
   DispatchMessage(&Message);
}
return Message.wParam;
}

long WINAPI WndProc(HWND hWnd,UINT iMessage,UINT wParam,LONG lParam)
{
HDC hDC;   //定义设备环境句柄.
HBRUSH hBrush;   //定义画刷句柄
HPEN hPen;   //定义画笔句柄
PAINTSTRUCT PtStr;//定义包含绘图信息的结构体变量
switch(iMessage)
{
case WM_PAINT:     //处理绘图消息
   hDC=BeginPaint(hWnd,&PtStr);   //获得设备环境指针
   SetWindowOrgEx(hDC,-200,-200,NULL); //设置原点坐标
   hPen=CreatePen(PS_DASH,1,RGB(255,0,0)); //建新画笔
   SelectObject(hDC,hPen);    //选入画笔
   Polyline(hDC,lpSin,100);   //绘制正弦曲线
   if(i<=25) //第一个1/4周期.
   {
    hPen=CreatePen(PS_DASH,1,RGB(255,0,0));
    hBrush=CreateHatchBrush(HS_BDIAGONAL,RGB(255,0,0));
    lRadious=(long)(dfRange*0.2+i%25*dfRange*0.4/25); //计算半径
   }
   else if(i<=50)//第二个1/4周期.
   {
    hPen=CreatePen(PS_DASH,1,RGB(0,255,0));
    hBrush=CreateHatchBrush(HS_DIAGCROSS,RGB(0,255,0));
    lRadious=(long)(dfRange*0.2+i%25*dfRange*0.4/25);
   }
   else if(i<=75)//第三个周期.
   {
    hPen=CreatePen(PS_DASH,1,RGB(0,0,255));
    hBrush=CreateHatchBrush(HS_CROSS,RGB(0,0,255));
    lRadious=(long)(dfRange*0.2+i%25*dfRange*0.4/25);
   }
   else//第四个周期.
   {
    hPen=CreatePen(PS_DASH,1,RGB(255,255,0));
    hBrush=CreateHatchBrush(HS_VERTICAL,RGB(255,255,0));
    lRadious=(long)(dfRange*0.2+i%25*dfRange*0.4/25);
   }
   SelectObject(hDC,hBrush); //选入画刷.
   SelectObject(hDC,hPen); //选入画笔.
   lCentreX=lpSin[i].x;   //圆心x坐标.
   lCentreY=lpSin[i].y;   //圆心y坐标.
   Ellipse(hDC,lCentreX-lRadious,lCentreY-lRadious,
               lCentreX+lRadious,lCentreY+lRadious);   //画圆
   i++;
   DeleteObject(hPen); //删除画笔
   DeleteObject(hBrush); //删除画刷
   EndPaint(hWnd,&PtStr); //删除设备环境指针
   Sleep(100);   //停0.1秒
   if(i<100) InvalidateRect(hWnd,NULL,1); //刷新用户区
   return 0;
case WM_DESTROY:   //关闭窗口.
   PostQuitMessage(0);  
   return 0;
default:
          return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}
}


(5)绘图与刷新。制订一种重新绘制图形的刷新方式,将图形绘制模块放在消息WM_PAINT的处理过程中,当窗口需要刷新时,通知窗口函数重新绘制图形以完成刷新工作。本例要求先使用画笔和画刷绘制一个矩形,然后使用红色网格绘制一个椭圆,再使用绿色点划线绘制椭圆的轴线。

#include <windows.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInst,LPSTR lpszCmdLine,int nCmdShow)
{
HWND hwnd;
MSG Msg;
WNDCLASS wndclass;
char lpszClassName[] = "基本绘图";
char lpszTitle[]= "My_Drawing";
wndclass.style = 0;
……    //填写属性
wndclass.lpszClassName = lpszClassName ;
if(!RegisterClass(&wndclass))
{
   MessageBeep(0);
   return FALSE;
}
hwnd = CreateWindow(…,………,…);
ShowWindow(hwnd, nCmdShow) ; UpdateWindow(hwnd);
while(GetMessage(&Msg,NULL,0,0))
{
   TranslateMessage(&Msg);
   DispatchMessage(&Msg);
}
return Msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
HPEN hP;     //定义画笔句柄
HBRUSH hB;    //定义画刷句柄
switch(message)
   {
case WM_PAINT: //通过响应WM_PAINT消息完成绘图工作
   hP=CreatePen(PS_DASHDOT,1,RGB(0,255,0));//自定义绿笔
        //所画线条为点划线,宽度为1
   hB=CreateHatchBrush(HS_CROSS,RGB(255,0,0));//红色网状
   hdc=BeginPaint(hwnd,&ps); //取得设备环境句柄
   SetMapMode(hdc,MM_TEXT); //设置映射模式,用缺省模式
                            //使用当前缺省画笔、画刷进行绘图
   Rectangle(hdc,130,60,270,200); //绘制矩形,并填充
   SelectObject(hdc,hB); //更新画刷,用“红色网状”
   Ellipse(hdc,130,70,270,190);//绘制椭圆,并填充
   SelectObject(hdc,hP); //更新画笔,选“自定义绿笔”
   MoveToEx(hdc,100,130,NULL); //使用当前画笔绘制轴线
   LineTo(hdc,300,130);
   MoveToEx(hdc,200,30,NULL);
   LineTo(hdc,200,230);
   EndPaint(hwnd,&ps);   //释放设备环境句柄
   DeleteObject(hP); //退出窗口时删除画笔
   DeleteObject(hB); //退出窗口时删除黑色画刷
   break;
case WM_DESTROY:
   PostQuitMessage(0);
   break;
default:
   return DefWindowProc(hwnd,message,wParam,lParam);
}
return 0;
}

(6)设置映像与使用映像模式实例。本例中的程序运行时,初始阶段按模式MM_TEXT绘图,图形为一个坐标系,以逻辑坐标系的原点为原点,X、Y轴分别是逻辑坐标系的X、Y轴。当用户按下‘A’键‘B’键或‘C’键时,产生WM_CHAR消息,将映像模式分别设置为ISOTROPIC、ANISOTROPIC或LOMETRIC,同时调用InvalidateRect函数刷新用户区。

#include <windows.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
int nMode=MM_TEXT;         //设置映像模式的初始值
……
LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
HPEN hPen;  
switch(message)
{
case WM_CHAR:      //按下不同的键时,设置不同的映像模式15.
   if(wParam=='a'||wParam=='A')
    nMode=MM_ISOTROPIC;
   else if(wParam=='b'||wParam=='B')
    nMode=MM_ANISOTROPIC;
   else if(wParam=='c'||wParam=='C')
    nMode=MM_LOMETRIC;
   else ;
InvalidateRect(hwnd,NULL,1);   //刷新用户区
break;
case WM_PAINT:
   hdc=BeginPaint(hwnd,&ps);    //取得设备环境句柄
   SetMapMode(hdc,nMode);              //设置映像模式
   SetWindowExtEx(hdc,15,15,NULL);    //设置窗口区域
   SetViewportExtEx(hdc,15,10,NULL);    //设置视口区域
   SetViewportOrgEx(hdc,120,120,NULL); //设置视口原点
   hPen=CreatePen(PS_SOLID,2,RGB(255,0,0)); //创建红色画笔
   SelectObject(hdc,hPen);     //将画笔选入设备环境
   //画坐标系,原点在视口原点
   LineTo(hdc,200,0);
   LineTo(hdc,195,-5);
   MoveToEx(hdc,200,0,NULL);
   LineTo(hdc,195,5);
   MoveToEx(hdc,0,0,NULL);
   LineTo(hdc,0,200);
   LineTo(hdc,-5,195);
   MoveToEx(hdc,0,200,NULL);
   LineTo(hdc,5,195);
   DeleteObject(hPen);
   EndPaint(hwnd,&ps);
   break;
case WM_DESTROY:
   PostQuitMessage(0); break;  
default:
   return DefWindowProc(hwnd,message,wParam,lParam);
}
return 0;
}

posted on 2010-11-23 10:54  carekee  阅读(1648)  评论(0编辑  收藏  举报