您的位置:首页 > 大数据 > 人工智能

绘图;BeginPaint;PAINTSTRUCT(&ps);SetArcDirection函数改变弧线的方向;LineDDA函数

2016-12-17 21:49 471 查看
转自:http://blog.csdn.net/tcjiaan/article/details/8533358

BeginPaint

HDC BeginPaint(

HWND hwnd, // 窗口的句柄

LPPAINTSTRUCT lpPaint // 绘制信息

);

PAINTSTRUCT

英文解释:This structure contains information that an application uses to paint the client area of a window owned by that application.

中文解释:该结构体包含了某应用程序用来绘制它所拥有的窗口客户区所需要的信息。

PAINTSTRUCT定义

typedef struct tagPAINTSTRUCT {

HDC hdc;

BOOL fErase;

RECT rcPaint;

BOOL fRestore;

BOOL fIncUpdate;

BYTE rgbReserved[32];

} PAINTSTRUCT, *PPAINTSTRUCT;

PAINTSTRUCT 结构体包含了用于绘制窗口客户区的信息。例如要更新的客户区的矩形区域的大小等等,MFC里的CPaintDC与之对应;

BeginPaint可以得到客户区设备描述表的句柄,GetDC也可以得到,MFC里的CClientDC与之对应。

hdc是用于绘制的句柄,

fErase如果为非零值则擦除背景,否则不擦除背景,

rcPaint 通过制定左上角和右下角的坐标确定一个要绘制的矩形范围,该矩形单位相对于客户区左上角,

后面三个参数都是系统预留的,编程一般用不到。

要进行绘制,首先要得到一个DC,啥是DC呢?按字面翻译叫设备上下文,也可以翻译为设备描述表,它主要指API为我们封装了一些与显示设备相关的交互操作,我们这里说的是图形的绘制,自然指的是显卡。当然,对于同一客观事物,世界上并不存在唯一的理解方案,技术上的东西最终拿来用的,不应该有硬性的去统一。我们之中的很多人,最大的失败在于,人家说要这样理解他就毫不怀疑地这样理解,权威人士说要这样这样,他就不经过大脑思考地跟着那样那样。

虽然我的母校是名不见经传的三流大学,但回忆我的大学,很幸运,我曾经遇到几位好老师,真正的好老师,不是那些所谓的叫兽砖家。记得某位老师说过:这本书,如果读完了你一无所获,那你太失败了;如果你把书中的内容都掌握了,勉强及格;如果你能把书中的所有观点全部推翻,你才是优秀的。

 

在许多情况下,我们绘图都是遵循先GetDC-----〉绘图------〉ReleaseDC,DC是一种资源,用完了要释放,我们到图书馆借书,看完了要还书。不过,在处理WM_PAINT消息时,调用BeginPaint函数后,开始绘图,画完了调用EndPaint。当然这个并不违背我们前面所说的使用完HDC要释放的道理,只是BeginPaint函数会自动调用GetDC,EndPaint会自动调用ReleaseDC。

好的,首先我们来写几个字吧。绘制文本可以使用DrawText函数,他的最后一个参数是文本的对齐格式,如左对齐、居中、右对齐等。

[cpp] view
plain copy

 print?

PAINTSTRUCT ps;  

switch(msg)  

{  

case WM_PAINT:  

        BeginPaint(hwnd, &ps);  

声明一个PAINTSTRUCT结构体的变量,然后传给BeginPaint函数,之后就可以画东西了。

[cpp] view
plain copy

 print?

DrawText(ps.hdc,L"床前明月光", -1, &rect, DT_CENTER);  

但是,如果我希望文本的颜色不是默认的黑色,我们可以考虑调用SetTextColor函数来设置颜色,之后我们绘制的所有文本都是这个颜色了,如果之后希望改变文本的颜色,就再次调用SetTextColor函数。

[cpp] view
plain copy

 print?

SetTextColor(ps.hdc, RGB(0,150,255));  

RGB宏可以通过三个值来确定颜色值,这个估计不用我介绍了,如果不懂RGB,可以去请教芙蓉姐姐。

 

我希望新绘制的文本在前一个文本的下一行,当然,你可能会说,用DrawText的时候把传给它的RECT改一下坐标就行了。这方法虽然可以,但我们不好调坐标。其实,我们如果知道文本字符的高度,那不就好办了吗,对的,要获得文本高度,可以调用GetTextMetrics函数。现在我们要用的工具都齐全了。

[cpp] view
plain copy

 print?

case WM_PAINT:  

    BeginPaint(hwnd, &ps);  

    TEXTMETRIC tm;  

    // 取得与文本相关的数据  

    GetTextMetrics(ps.hdc, &tm);  

    RECT rect;  

    rect.top = 0L;  

    rect.left = ps.rcPaint.left;  

    rect.right = ps.rcPaint.right;  

    rect.bottom = rect.top + tm.tmHeight;  

    // 第一行文本  

    SetTextColor(ps.hdc, RGB(0,150,255));  

    DrawText(ps.hdc,L"床前明月光", -1, &rect, DT_CENTER);  

    // 第二行文本  

    rect.top += tm.tmHeight;  

    rect.bottom += tm.tmHeight;  

    SetTextColor(ps.hdc, RGB(220, 12, 50));  

    DrawText(ps.hdc, L"疑是地上霜", -1, &rect, DT_LEFT);  

    // 第三行文本  

    rect.top += tm.tmHeight;  

    rect.bottom += tm.tmHeight;  

    SetTextColor(ps.hdc, RGB(30,255,7));  

    DrawText(ps.hdc, L"举头望明月", -1, &rect, DT_RIGHT);  

    // 第四行文本  

    rect.top += tm.tmHeight;  

    rect.bottom += tm.tmHeight;  

    SetTextColor(ps.hdc, RGB(0,40,210));  

    DrawText(ps.hdc, L"低头思故乡", -1, &rect, DT_RIGHT);  

    EndPaint(hwnd, &ps);  

    return 0;  

这个不难理解吧,就是每一行文本的矩形区域得顶部和底部坐标分别加上文本的高度。

现在可以看看效果了。



 

接下来,我们画几条弧线。绘制弧线使用Arc函数,第一个参数是目标HDC,随后的4个参数用于确定弧线所在的位置的矩形,最后4个参数是确定弧线的开始点和结束点的坐标。

[cpp] view
plain copy

 print?

BOOL  WINAPI Arc(  

      HDC hdc, //DC的句柄  

      int x1, // 矩形的左坐标  

      int y1, //矩形上坐标  

      int x2,//矩形的右坐标  

      int y2, //矩形的下坐标  

      int x3, //起点x坐标  

      int y3, //起点y坐标  

      int x4, //终点x坐标  

      int y4 //终点y坐标  

);  

在默认情况下,弧线是逆时针方向的。

[cpp] view
plain copy

 print?

// 绘制弧线  

HPEN pen = CreatePen(PS_SOLID, 2, RGB(200, 100, 20));//创建笔  

// 将笔选到DC中  

auto oldObj = SelectObject(ps.hdc, pen);  

// 画弧线  

Arc(ps.hdc, 20, 100,  300, 300, 39, 110, 280, 285);  

Arc(ps.hdc, 200, 160, 390, 400, 300,350, 380,165);  

// 画完之后,把原先的笔选回去  

SelectObject(ps.hdc, oldObj);  

// 清理  

DeleteObject(pen);  

上面代码将画出如下图所示的弧线。



 

默认是逆时针方向,现在我想画顺时针方向的弧线。看下面例子,通过SetArcDirection函数改变弧线的方向。

[cpp] view
plain copy

 print?

/* 

AD_COUNTERCLOCKWISE表示逆时针方向 

AD_CLOCKWISE表示顺时针方向 

*/  

SetArcDirection(ps.hdc, AD_CLOCKWISE);  

Arc(ps.hdc, 20,150, 460,450, 90,162, 85,300);  



 

 

下面介绍一下LineDDA函数,这个家伙不简单,为啥?因为I它可以通过回调函数来对一条线段中不同的点进行分别处理。其回调函数如下:

[cpp] view
plain copy

 print?

VOID CALLBACK LineDDAProc(int x, int y, LPARAM lpData);  

最后一个参数是长指针,我们可以将一个HDC的地址传给它。

因为需要回调函数,我们得先写好回调函数,但是,在文件的前面要先声明一下,C语言的函数如果在调用之后定义,就必须先声明,不然编译的时候找不到。

[cpp] view
plain copy

 print?

VOID CALLBACK LineDDAProc(int x, int y, LPARAM lpData)  

{  

    // 从参数中取得HDC  

    HDC hdc = *((HDC*)lpData);  

    // 不同位置的线段设置不同的颜色  

    int type=0;  

    if(x <= 510 || y <= 200)  

    {  

        type = 0;  

    }  

    else if((x > 510 && x <= 700) ||  

        (y > 720 && y <= 360))  

    {  

        type = 1;  

    }  

    else  

    {  

        type = 2;  

    }  

  

    // 根据不同情况着色  

    switch(type)  

    {  

    case 0:  

        SetPixel(hdc,x,y,RGB(0,255,0));  

        break;  

    case 1:  

        SetPixel(hdc,x,y,RGB(0,0,255));  

        break;  

    case 2:  

        SetPixel(hdc,x,y,RGB(255,0,0));  

        break;  

    default:  

        SetPixel(hdc,x,y,RGB(255,0,0));  

    }  

}  

接着在相应WM_PAINT消息的时候调用LineDDA函数。

[cpp] view
plain copy

 print?

LineDDA(420,130,800,470,LineDDAProc, (LPARAM)&ps.hdc);  

结果你会看到,画出来的线段是有三种颜色的。



 

完整的代码如下:

[cpp] view
plain copy

 print?

#include <Windows.h>  

LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);  

  

VOID CALLBACK LineDDAProc(int x, int y, LPARAM lpData);  

  

int WINAPI WinMain(HINSTANCE hTheApp,  

                    HINSTANCE hPrevApp,  

                    LPSTR cmdline,  

                    int nShow)  

{  

    WNDCLASS wc = {   };  

    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);  

    wc.hInstance = hTheApp;  

    wc.lpfnWndProc = WindowProc;  

    wc.lpszClassName = L"MyApp";  

    wc.style = CS_HREDRAW | CS_VREDRAW;  

      

    RegisterClass(&wc);  

    HWND hwnd = CreateWindow(L"MyApp",  

        L"我的应用程序",  

        WS_OVERLAPPEDWINDOW | WS_VISIBLE,  

        35,  

        28,  

        600,  

        500,  

        NULL,  

        NULL,  

        hTheApp,  

        NULL);  

    if(hwnd == NULL)  

        return -1;  

    // 消息循环  

    MSG msg;  

    while(GetMessage(&msg, NULL, 0, 0))  

    {  

        TranslateMessage(&msg);  

        DispatchMessage(&msg);  

    }  

}  

  

LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)  

{  

    PAINTSTRUCT ps;  

    switch(msg)  

    {  

    case WM_DESTROY:  

        PostQuitMessage(0);  

        return 0;  

    case WM_PAINT:  

        BeginPaint(hwnd, &ps);  

        TEXTMETRIC tm;  

        // 取得与文本相关的数据  

        GetTextMetrics(ps.hdc, &tm);  

        RECT rect;  

        rect.top = 0L;  

        rect.left = ps.rcPaint.left;  

        rect.right = ps.rcPaint.right;  

        rect.bottom = rect.top + tm.tmHeight;  

        // 第一行文本  

        SetTextColor(ps.hdc, RGB(0,150,255));  

        DrawText(ps.hdc,L"床前明月光", -1, &rect, DT_CENTER);  

        // 第二行文本  

        rect.top += tm.tmHeight;  

        rect.bottom += tm.tmHeight;  

        SetTextColor(ps.hdc, RGB(220, 12, 50));  

        DrawText(ps.hdc, L"疑是地上霜", -1, &rect, DT_LEFT);  

        // 第三行文本  

        rect.top += tm.tmHeight;  

        rect.bottom += tm.tmHeight;  

        SetTextColor(ps.hdc, RGB(30,255,7));  

        DrawText(ps.hdc, L"举头望明月", -1, &rect, DT_RIGHT);  

        // 第四行文本  

        rect.top += tm.tmHeight;  

        rect.bottom += tm.tmHeight;  

        SetTextColor(ps.hdc, RGB(0,40,210));  

        DrawText(ps.hdc, L"低头思故乡", -1, &rect, DT_RIGHT);  

        // 绘制弧线  

        HPEN pen = CreatePen(PS_SOLID, 3, RGB(200, 100, 20));//创建笔  

        // 将笔选到DC中  

        auto oldObj = SelectObject(ps.hdc, pen);  

        // 画弧线  

        /*Arc(ps.hdc, 20, 100,  300, 300, 39, 110, 280, 285); 

        Arc(ps.hdc, 200, 160, 390, 400, 300,350, 380,165);*/  

  

        /* 

        AD_COUNTERCLOCKWISE表示逆时针方向 

        AD_CLOCKWISE表示顺时针方向 

        */  

        SetArcDirection(ps.hdc, AD_CLOCKWISE);  

        Arc(ps.hdc, 20,150, 300,450, 90,162, 85,300);  

        // 画完之后,把原先的笔选回去  

        SelectObject(ps.hdc, oldObj);  

        // 清理  

        DeleteObject(pen);  

        // 分段线条  

        LineDDA(420,130,800,470,LineDDAProc, (LPARAM)&ps.hdc);  

        EndPaint(hwnd, &ps);  

        return 0;  

    }  

    return DefWindowProc(hwnd, msg, wParam, lParam);  

}  

  

VOID CALLBACK LineDDAProc(int x, int y, LPARAM lpData)  

{  

    // 从参数中取得HDC  

    HDC hdc = *((HDC*)lpData);  

    // 不同位置的线段设置不同的颜色  

    int type=0;  

    if(x <= 510 || y <= 200)  

    {  

        type = 0;  

    }  

    else if((x > 510 && x <= 700) ||  

        (y > 720 && y <= 360))  

    {  

        type = 1;  

    }  

    else  

    {  

        type = 2;  

    }  

  

    // 根据不同情况着色  

    switch(type)  

    {  

    case 0:  

        SetPixel(hdc,x,y,RGB(0,255,0));  

        break;  

    case 1:  

        SetPixel(hdc,x,y,RGB(0,0,255));  

        break;  

    case 2:  

        SetPixel(hdc,x,y,RGB(255,0,0));  

        break;  

    default:  

        SetPixel(hdc,x,y,RGB(255,0,0));  

    }  

}  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐