当前位置:C++技术网 > 精选软件 > 使用SetPixel在客户区自由绘画的功能实现

使用SetPixel在客户区自由绘画的功能实现

更新时间:2015-12-16 00:02:46浏览次数:1+次

    我们学习GDI,最开始就是接触的SetPixel和GetPixel两个画图函数,也是两个最简单的函数。我们这里利用SetPixel开始作画。
    作画的实现思路就是:用鼠标左键按下时拖动鼠标绘画,释放左键停止绘画。用一个静态布尔变量,记录是否开始绘画了,如果开始绘画了,布尔变量为真,即鼠标左键按下时设置这个值为真。那么在鼠标移动的点设置该点像素点为一个颜色即可。然后释放鼠标左键时,让布尔变量为假,表示停止作画,此时鼠标移动的消息不再执行绘图操作。然后右击鼠标,则让客户区失效,导致WM_PAINT重绘客户区,即达到清除客户区的目的。
    下面是程序绘图的效果图:
    SetPixel画图
    你仔细观察,可以发现,划线的连续有地方都是断断续续的。这个是因为WM_MOUSEMOVE因为产生消息的频率太高,所以系统将一些消息丢弃了,所以无法连续显示。所以,你可以移动慢一点,让消息能够及时处理而不至于被丢弃,这样就可以形成连续的线条。
    这个问题只是让你认识到SetPixel函数确实可以实现这个功能,然而却存在不连续的问题,所以我会在后面用划线的方式来实现连续的线条,不管你移动鼠标多快,都可以是连续的线条哦。
    以下是完整的源代码:
#include "windows.h"
#include <Windowsx.h>//GET_X_LPARAM,GET_Y_LPARAM宏需要这个头文件
#include <tchar.h>
// - 项目是Unicode字符集
LRESULT CALLBACK WinProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
    HDC hdc;
    PAINTSTRUCT ps;
    static bool bisPaint=false;
    TCHAR Info[100]=_T("【C++技术网http://www.cjjjs.com】");
    int iRed,iGreen,iBlue;
    switch (message)
    {
     case WM_PAINT:
         hdc = BeginPaint(hwnd,&ps);//会清除无效矩形
         TextOut(hdc,0,10,Info,lstrlen(Info));
         EndPaint(hwnd,&ps);
         return 0;
     case WM_LBUTTONDOWN:
         bisPaint=true;//开始作画
         return 0;
     case WM_LBUTTONUP:
         bisPaint=false;//松开鼠标,结束绘画
         return 0;
     case WM_RBUTTONDOWN:
         InvalidateRect(hwnd,NULL,TRUE);//右击擦除客户区
         return 0;
     case WM_MOUSEMOVE:
         if(bisPaint)//如果按着鼠标时,表示在作画,因此可以开始绘制
         {
             hdc = GetDC(hwnd);
             SetPixel(hdc,GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam),RGB(255,0,0));    //-单像素
             SetPixel(hdc,GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam)+1,RGB(255,0,0));    //-单像素
             SetPixel(hdc,GET_X_LPARAM(lParam)+1,GET_Y_LPARAM(lParam),RGB(255,0,0));    //-单像素
             SetPixel(hdc,GET_X_LPARAM(lParam)+1,GET_Y_LPARAM(lParam)+1,RGB(255,0,0));    //-单像素
             ReleaseDC(hwnd,hdc);
         }
         return 0;
     case WM_DESTROY:
         PostQuitMessage(0);
         return 0;
     default:
         return DefWindowProc(hwnd, message, wParam, lParam);
    }
}
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrev,LPSTR lpCmd,int iShow)
{
    TCHAR ClassName[] = _T("MyClass");
    TCHAR title1[] = _T("C++技术网http://www.cjjjs.com");
    WNDCLASS wndClass;
    wndClass.cbClsExtra=0;
    wndClass.cbWndExtra=0;
    wndClass.hbrBackground= (HBRUSH)GetStockObject(BLACK_BRUSH);
    wndClass.hCursor=LoadCursor(NULL,IDC_ARROW);
    wndClass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
    wndClass.hInstance = hInstance;
    wndClass.lpfnWndProc = WinProc;
    wndClass.lpszClassName = ClassName;
    wndClass.lpszMenuName=NULL;
    wndClass.style=CS_HREDRAW|CS_VREDRAW;

    if(!RegisterClass(&wndClass))
    {
        return 0;
    }

    HWND hwnd = CreateWindow(ClassName,title1,WS_OVERLAPPEDWINDOW,0,0,440,400,NULL,NULL,hInstance,NULL);
    ShowWindow(hwnd,SW_SHOWNORMAL);

    MSG msg;
    while (GetMessage(&msg,NULL,0,0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}

    代码说明:在WM_MOUSEMOVE消息处理中,我们用了四个SetPixel函数,主要就是因为单个像素太小了,所以将画的点扩大为四个像素点。WM_MOUSEMOVE消息的lParam参数存储的是当前鼠标的坐标,通过宏GET_X_LPARAM和GET_Y_LPARAM可以分别得到鼠标光标当前的坐标值。