windows程序设计之GDI简介

最近在做一个有关激光笔的小项目,和学长们一起做的。里面还有硬件成份,现在因为才开始做,我主要做软件上面的东西,当然技术含量是很少的抓狂···诶,学了一年左右了,水平还是没很大长进刚刚C入门,SDK也只能说勉强算是入门了吧。项目里面有一部分是要绘制出来鼠标的移动轨迹的,我就去重新看了下GDI,发现自己以前没写过这些东西,印象就是不深刻啊,于是就温习了下。重新看了下<>和<>,ctrl+c和ctrl+v出来下面个实验品,然后做了些笔记,我还是记得学长讲得那句话:博客就是用来记录自己成长的地方。无论有什么学到的,都可以写上来,无论含量高不高,总能在自己以后有一天需要的时候想起来,并且找到,这大概和老师说的好记性不如让笔头差不多吧.

下面是自己一些简单的总结:

windows GDI绘图
Graphics Device Interface:图形设备接口
GDI是GraphicsDeviceInterface的缩写,含义是图形设备接口,它的主要任务是负责系统与绘图程序之间的信息交换,处理所有Windows程序的图形输出。
在Windows操作系统下,绝大多数具备图形界面的应用程序都离不开GDI,我们利用GDI所提供的众多函数就可以方便的在屏幕、打印机及其它输出设备上输出图形,文本等操作。GDI的出现使程序员无需要关心硬件设备及设备驱动,就可以将应用程序的输出转化为硬件设备上的输出,实现了程序开发者与硬件设备的隔离,大大方便了开发工作。

1.资源使用
// 初始的颜色
BYTE bRed = 0;
BYTE bGreen = 0;
BYTE bBlue = 0;
// 笔的颜色 正黑
COLORREF cPen = RGB(bRed, bGreen, bBlue);
//画笔的设置
HPEN CreatePen(
__in int fnPenStyle,
__in int nWidth,
__in COLORREF crColor
);
HPEN hpen;
hpen = CreatePen(PS_SOLID, 10, cPen); //画笔基本属性

//画刷的设置
HBRUSH hbrush;
COLORREF cBrush = RGB(233, GetGValue(cPen),255);
hbrush = CreateSolidBrush(cBrush);
// 释放资源
DeleteObject(hpen);
DeleteObject(hbrush);

2.获取DC。获取了DC就相当于获取了绘画的资格。
HDC hDC = GetDC(hWnd);//参数是NULL时获取的是整个显示器的DC,若是句柄就是指定窗口的DC。

3.将DC设置成对象目标句柄。将图形对象选入DC中,这样DC中原有的类型图形对象就会被新的对象替换。
SelectObject(hDC, hpen);
SelectObject(hDC, hbrush);
这样绘画的时候就可以改变默认的DC属性。

4.绘画区域的变化
GetClientRect(hWnd, &rect);这里获取的是客户区域的大小,是以客户区左上角为坐标原点进行创建的。因此比如在处理WM_MOUSEMOVE等鼠标消息的时候,传进来的lParam参数中包含的坐标也是相对于客户端的。要想转化成屏幕坐标可以用下面的方法:
//转换窗口有效区为屏幕座标
POINT point;
point.x = 0, point.y = 0;
ClientToScreen(hWnd,&point);
你要是想把光标限制在客户区内,可以这样:
//将光标限定在窗口有效区内
rect.top = point.y;
rect.left = point.x;
rect.bottom += rect.top;
rect.right += rect.left;
ClipCursor(&rect); //rect一定要是屏幕座标
下面是获取屏幕坐标的函数
POINT pt;
GetCursorPos(&pt);
这里获取的坐标就是相对屏幕左上角的坐标。若是要转化成客户区坐标可以用
ScreenToClient(hWnd,&point);

5.绘制线条
移到指定的点

下面是我修改的一个绘制鼠标轨迹的小程序

#define MAXGUIDESEGMENTS 1000
#define MyAlloc(dwSize) HeapAlloc(GetProcessHeap(),0,dwSize)
#define MyFree(lpMem) HeapFree(GetProcessHeap(),0,lpMem);

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
BOOL GetGuideLine(HWND hWnd, LPPOINT *lpPoint, LPDWORD lpdwNumPts);

LONG clsCur;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT ("LineDemo") ;
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))
{
MessageBox (NULL, TEXT ("Program requires Windows NT!"),
szAppName, MB_ICONERROR) ;
return 0 ;
}

hwnd = CreateWindow (szAppName, TEXT ("Line Demonstration"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL) ;

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 = NULL ;
static LPPOINT lpRed = NULL;
static DWORD dwRed = 0;
switch (message)
{
case WM_CREATE:
hDC = GetDC(hwnd);
break;

case WM_LBUTTONDOWN:
//取得窗口有效区
RECT rect;
GetClientRect(hwnd,&rect);

//转换窗口有效区为屏幕座标
POINT point;
point.x = 0, point.y = 0;
ClientToScreen(hwnd,&point);
rect.top = point.y;
rect.left = point.x;
rect.bottom += rect.top;
rect.right += rect.left;

ClipCursor(&rect); //rect一定要是屏幕座标

if (!clsCur) {
clsCur = GetClassLong(hwnd,GCL_HCURSOR); //取当前窗口的光标
}
SetClassLong(hwnd,GCL_HCURSOR,NULL); //设置当前窗口的光标为NULL
SetCursor(LoadCursor(NULL, IDC_CROSS)); //设置当前光标为十字形

GetGuideLine(hwnd, &lpRed, &dwRed);

break;
case WM_DESTROY:
if (lpRed)
MyFree(lpRed);
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}

BOOL GetGuideLine(HWND hWnd, LPPOINT *lpPoint, LPDWORD lpdwNumPts)
{
MSG msg;
HDC hDC = GetDC(hWnd);
BOOL bFirstTime = TRUE;
DWORD dwPos = 0;
RECT rect;
static HPEN hpen;

hpen = CreatePen(PS_SOLID,3, RGB(0,255,0));
SelectObject(hDC,hpen);

GetClientRect(hWnd, &rect);
// 为点数组分配空间
*lpPoint = (LPPOINT)MyAlloc(MAXGUIDESEGMENTS * sizeof(POINT));
SetCapture(hWnd); // 设置鼠标捕获器
// 将客户区填充为白色
GetClientRect(hWnd, &rect);
PatBlt(hDC, 0, 0, rect.right, rect.bottom, WHITENESS);

while(1)
{
// 过滤所有鼠标消息
WaitMessage();
if (PeekMessage(&msg,NULL,WM_MOUSEFIRST,WM_MOUSELAST,PM_REMOVE))
{
// 判断是否在客户区中
if ((LOWORD(msg.lParam) < rect.right) && (HIWORD(msg.lParam) <
rect.bottom))
{
// 是否第一次收到消息
if (bFirstTime)
{
bFirstTime = FALSE;
// 如果是第一次将笔的起点移动到鼠标点击的位置
MoveToEx(hDC, LOWORD(msg.lParam), HIWORD(msg.lParam),
NULL);
}
// 是否达到了最大点数
if (dwPos < MAXGUIDESEGMENTS)
{
// 鼠标的移动会产生鼠标消息,每收到一次消息保存一个点
(*lpPoint)[dwPos].x = LOWORD(msg.lParam);
(*lpPoint)[dwPos].y = HIWORD(msg.lParam);
// 绘制到鼠标所在的点
LineTo(hDC, (*lpPoint)[dwPos].x, (*lpPoint)
[dwPos].y);
dwPos++;
}
}
}
if (msg.message == WM_RBUTTONDOWN)
{
ClipCursor(NULL);
SetClassLong(hWnd,GCL_HCURSOR, clsCur);
SetCursor((HCURSOR)clsCur);
break;
}
else
continue;
}

*lpdwNumPts = dwPos;
ReleaseDC(hWnd, hDC);
ReleaseCapture();
DeleteDC( hDC );

return TRUE;
}

最近的时间越来越紧啊···专业课越来越难,自己课余学计算机的时间也越来越少,真是后后悔自己没去计算机专业额,不过事在人为,努力就好!昨天看到一句比较好的话:一个优秀的程序员:勤奋+执着!我看着很有感触,有时觉得自己花那么多时间面对代码,是否值得···不过我想有付出就会有回报的!!

标签:SDK