第一个要介绍的是画笔。
通常我们理解的划线,应该是在划线函数中指明,我这条线画出来应该有多宽,线的类型是什么(比如虚线,点划线,实现)等等。而且很多地方就是这样做的,比如开源计算机视觉库OpenCV,Matlab等等中就是这样。但是Windows程序设计却是另一种思路:我先设计一个画笔,这根笔决定了我划线的颜色,粗细,线型等等。然后选择这根笔,最后划线。这样做好处其实也很多,大家如果习惯了word或者visio里面的绘图的话,也不难理解这样做的方便之处。
举一个例子:
#include <windows.h>
#include <math.h>
#define NUM 1000
#define TWOPI (2*3.14159)
#define LOGWIDE 4000
#define LOGHIGH 3000
LRESULT CALLBACK WndProc (HWND,UINT,WPARAM,LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, //当前实例句柄
HINSTANCE hPrevInstance, //先前实例句柄
LPSTR lpCmdLine, //命令行
int iCmdShow) //显示状态
{
static TCHAR szAppName[] = TEXT("画图");
//窗口句柄
HWND hwnd;
//消息
MSG msg;
//窗口类
WNDCLASS wndclass;
//窗口风格:当移动窗口或者改变大小时重绘窗口
wndclass.style = CS_HREDRAW | CS_VREDRAW;
//指明回调函数
wndclass.lpfnWndProc = WndProc;
//额外的比特用来确认下一个窗口类的位置,暂时不用
wndclass.cbClsExtra = 0;
//额外的比特用来确认下一个窗口实例的位置,暂时不用
wndclass.cbWndExtra = 0;
//实例句柄
wndclass.hInstance = hInstance;
//装载图标
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
//装载光标
wndclass.hCursor = LoadCursor(NULL,IDC_ARROW);
//背景为白色
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
//菜单:暂时没有
wndclass.lpszMenuName = NULL;
//窗口类名
wndclass.lpszClassName = szAppName;
//注册窗口
if(!RegisterClass(&wndclass))
{
return -1;
}
//创建窗口
hwnd = CreateWindow(szAppName, //窗口类的名称,必须是已经注册的
TEXT("我的画图"), //窗口标题
WS_OVERLAPPEDWINDOW, //窗口风格
CW_USEDEFAULT, //X坐标
CW_USEDEFAULT, //Y坐标
CW_USEDEFAULT, //宽度
CW_USEDEFAULT, //高度
NULL, //父窗口句柄
NULL, //菜单窗口句柄
hInstance, //高级版本的windos忽略
NULL);
//显示窗口
//ShowWindow(hwnd,SW_SHOWNA);
ShowWindow (hwnd, iCmdShow);
//更新窗口
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;
HPEN hPen;
PAINTSTRUCT ps;
int i;
static int cxClient,cyClient;
POINT apt[NUM];
switch(message)
{
case WM_SIZE:
cxClient = LOWORD(lParam);
cyClient = HIWORD(lParam);
return 0;
case WM_PAINT:
hdc = BeginPaint(hwnd,&ps);
for(i = 0; i < 256;i++)
{
/*
//创建画笔:参数为:画笔风格,画笔宽度,画笔颜色
hPen = CreatePen(PS_SOLID,i,RGB(i,0,0));
SelectObject(hdc,hPen);
MoveToEx(hdc,300,200,NULL);
LineTo(hdc,300,500);
DeleteObject(hPen);
Sleep(10);
*/
MoveToEx(hdc, 0,cyClient/2,NULL);
LineTo (hdc,cxClient,cyClient/2);
MoveToEx(hdc, 0,cyClient/2,NULL);
//画正弦曲线
for(i = 0; i < NUM;i++)
{
hPen = CreatePen(PS_SOLID,(int)(i/10),RGB((int)(i/4),0,0));
SelectObject(hdc,hPen);
apt[i].x = i * cxClient / NUM;
apt[i].y = (int)(cyClient /2*(1-sin(TWOPI *i/NUM)));
LineTo(hdc,apt[i].x,apt[i].y);
DeleteObject(hPen);
//Sleep(10);
}
}
EndPaint(hwnd,&ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd,message,wParam,lParam);
}
还是画正弦曲线,但是每画一笔,我都要改变线的宽度和颜色,其中(i/10)和(i/4)仅仅是为了让宽度和颜色的变化不会太快。
然后要介绍的是关于写字方面的内容DrawText。
首先要明白,你在窗口上写字DrawText时,要注意3中颜色:第一是背景的颜色,这通过wndclass.hbrBackground = (HBRUSH) GetStockObject (GRAY_BRUSH);改变;第二是你写的那些字颜色,通过SetTextColor(hdc,RGB(255,0,0));改变;第三是你写的那些字的背景颜色,就是说你写的那些字,占用了一个个方格,这些格子的背景是什么颜色的,这通过SetBkColor(hdc,RGB(128,128,128));来改变。但在通常情况下,我们把字的背景设为透明SetBkMode(hdc,TRANSPARENT);,让它随着窗口颜色变化而变化。下面我们看看这个简单的程序:
#include <windows.h>
#include <math.h>
LRESULT CALLBACK WndProc (HWND,UINT,WPARAM,LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, //当前实例句柄
HINSTANCE hPrevInstance, //先前实例句柄
LPSTR lpCmdLine, //命令行
int iCmdShow) //显示状态
{
static TCHAR szAppName[] = TEXT("画图");
//窗口句柄
HWND hwnd;
//消息
MSG msg;
//窗口类
WNDCLASS wndclass;
//窗口风格:当移动窗口或者改变大小时重绘窗口
wndclass.style = CS_HREDRAW | CS_VREDRAW;
//指明回调函数
wndclass.lpfnWndProc = WndProc;
//额外的比特用来确认下一个窗口类的位置,暂时不用
wndclass.cbClsExtra = 0;
//额外的比特用来确认下一个窗口实例的位置,暂时不用
wndclass.cbWndExtra = 0;
//实例句柄
wndclass.hInstance = hInstance;
//装载图标
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
//装载光标
wndclass.hCursor = LoadCursor(NULL,IDC_ARROW);
//背景为白色
//wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
//背景为灰色
wndclass.hbrBackground = (HBRUSH) GetStockObject (GRAY_BRUSH);
//菜单:暂时没有
wndclass.lpszMenuName = NULL;
//窗口类名
wndclass.lpszClassName = szAppName;
//注册窗口
if(!RegisterClass(&wndclass))
{
return -1;
}
//创建窗口
hwnd = CreateWindow(szAppName, //窗口类的名称,必须是已经注册的
TEXT("我的画图"), //窗口标题
WS_OVERLAPPEDWINDOW, //窗口风格
CW_USEDEFAULT, //X坐标
CW_USEDEFAULT, //Y坐标
CW_USEDEFAULT, //宽度
CW_USEDEFAULT, //高度
NULL, //父窗口句柄
NULL, //菜单窗口句柄
hInstance, //高级版本的windos忽略
NULL);
//显示窗口
//ShowWindow(hwnd,SW_SHOWNA);
ShowWindow (hwnd, iCmdShow);
//更新窗口
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;
HPEN hPen;
PAINTSTRUCT ps;
int i;
static int cxClient,cyClient;
RECT rect;
switch(message)
{
case WM_SIZE:
cxClient = LOWORD(lParam);
cyClient = HIWORD(lParam);
return 0;
case WM_PAINT:
hdc = BeginPaint(hwnd,&ps);
//设置背景颜色
//SetBkColor(hdc,RGB(128,128,128));
//将背景模式:透明
SetBkMode(hdc,TRANSPARENT);
//将背景模式:不透明
//SetBkMode(hdc,OPAQUE);
//设置字的颜色
SetTextColor(hdc,RGB(255,0,0));
//获取客户区坐标
GetClientRect(hwnd,&rect);
DrawText(hdc,TEXT("Hello, Windows7!"),-1,&rect,DT_SINGLELINE | DT_CENTER | DT_VCENTER);
EndPaint(hwnd,&ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd,message,wParam,lParam);
}