程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> Win32開發入門(8) 繪圖(A)

Win32開發入門(8) 繪圖(A)

編輯:關於C++

從本篇開始,我就不吹牛皮,那就吹吹兔皮吧。說說與繪圖有關的東東。

要進行繪制,首先 要得到一個DC,啥是DC呢?按字面翻譯叫設備上下文,也可以翻譯為設備描述表,它主要指API為我們 封裝了一些與顯示設備相關的交互操作,我們這裡說的是圖形的繪制,自然指的是顯卡。當然,對於同 一客觀事物,世界上並不存在唯一的理解方案,技術上的東西最終拿來用的,不應該有硬性的去統一。 我們之中的很多人,最大的失敗在於,人家說要這樣理解他就毫不懷疑地這樣理解,權威人士說要這樣 這樣,他就不經過大腦思考地跟著那樣那樣。

雖然我的母校是名不見經傳的三流大學,但回憶 我的大學,很幸運,我曾經遇到幾位好老師,真正的好老師,不是那些所謂的叫獸磚家。記得某位老師 說過:這本書,如果讀完了你一無所獲,那你太失敗了;如果你把書中的內容都掌握了,勉強及格;如 果你能把書中的所有觀點全部推翻,你才是優秀的。

在許多情況下,我們繪圖都是遵循先 GetDC-----〉繪圖------〉ReleaseDC,DC是一種資源,用完了要釋放,我們到圖書館借書,看完了要 還書。不過,在處理WM_PAINT消息時,調用BeginPaint函數後,開始繪圖,畫完了調用EndPaint。當然 這個並不違背我們前面所說的使用完HDC要釋放的道理,只是BeginPaint函數會自動調用GetDC, EndPaint會自動調用ReleaseDC。

好的,首先我們來寫幾個字吧。繪制文本可以使用DrawText函 數,他的最後一個參數是文本的對齊格式,如左對齊、居中、右對齊等。

PAINTSTRUCT ps;   

  
switch(msg)     
{     
case WM_PAINT:     
        BeginPaint(hwnd, &ps);

聲明一個PAINTSTRUCT結構體的變量,然後傳給 BeginPaint函數,之後就可以畫東西了。

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

但是,如果我希望文本的顏色不是默認的黑色,我們可以考慮調用 SetTextColor函數來設置顏色,之後我們繪制的所有文本都是這個顏色了,如果之後希望改變文本的顏 色,就再次調用SetTextColor函數。

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

RGB宏可 以通過三個值來確定顏色值,這個估計不用我介紹了,如果不懂RGB,可以去請教芙蓉姐姐。

我 希望新繪制的文本在前一個文本的下一行,當然,你可能會說,用DrawText的時候把傳給它的RECT改一 下坐標就行了。這方法雖然可以,但我們不好調坐標。其實,我們如果知道文本字符的高度,那不就好 辦了嗎,對的,要獲得文本高度,可以調用GetTextMetrics函數。現在我們要用的工具都齊全了。

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個參數是確定弧線的開始點和結束點的坐標。

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坐標     
);

在默認情況下,弧線是逆時針方向的。

// 繪制弧線     
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函數 改變弧線的方向。

/*    
AD_COUNTERCLOCKWISE表示逆時針方向    
AD_CLOCKWISE表示順時針方向    
*/ 
SetArcDirection(ps.hdc, AD_CLOCKWISE);     
Arc(ps.hdc, 20,150, 460,450, 90,162, 85,300);

下面介紹一下LineDDA函數,這個家伙不簡單,為啥?因為I它可以通過回調函數來對一條線 段中不同的點進行分別處理。其回調函數如下:

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

最後 一個參數是長指針,我們可以將一個HDC的地址傳給它。

因為需要回調函數,我們得先寫好回調 函數,但是,在文件的前面要先聲明一下,C語言的函數如果在調用之後定義,就必須先聲明,不然編 譯的時候找不到。

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函數。

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

結果你會看到,畫出來的線段是有三 種顏色的。

完整的代碼如下:

#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));     
    }     
}
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved