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

Win32開發入門(10) 繪圖(C)

編輯:關於C++

今天我們來欣賞一下用於填充圖形的函數,當然我不會逐個去介紹,因為我們參考MSDN直接套參數 就可以了。

SetDCBrushColor函數有必要扯一下,它的聲明如下:

COLORREF 

SetDCBrushColor(     
  __in  HDC hdc,     
  __in  COLORREF crColor     
);

第二個參數,通過RGB宏產生COLORREF傳進去就可以了,比如這樣:

SetDCBrushColor(ps.hdc,RGB(211,254,41));

但是,如果只是調用這個函數,你會發現 在繪圖的時候,畫刷的顏色還是沒有變化,因為我們還沒有將HBRUSH的默認畫刷DC_BRUSH選到DC中去。 所以,在調用SetDCBrushColor之前,要把默認的畫刷先放到設備上下文,默認畫刷可以通過 GetStockObject(DC_BRUSH)獲得。

SelectObject(ps.hdc,GetStockObject(DC_BRUSH));

接下來我們可以嘗試填充幾個圖形試試,如矩形、橢圓、餅圖等。

case WM_PAINT:     
    {     
        BeginPaint(hwnd,&ps);     
        SelectObject(ps.hdc,GetStockObject(DC_BRUSH));     
        SetDCBrushColor(ps.hdc,RGB(0,0,255));     
        Rectangle(ps.hdc,20,18,68,50);     
        SetDCBrushColor(ps.hdc,RGB(220,32,70));     
        Rectangle(ps.hdc,125,100,230,300);     
        SetDCBrushColor(ps.hdc,RGB(30,235,12));     
        Ellipse(ps.hdc,270,80,390,223);     
        SetDCBrushColor(ps.hdc,RGB(35,160,242));     
        Chord(ps.hdc,185,260,420,480,190,260,405,479);     
        SetDCBrushColor(ps.hdc,RGB(211,254,41));     
        Pie(ps.hdc,35,320,300,600,56,470,60,360);     
        EndPaint(hwnd,&ps);     
    }     
    return 0;

每一次調用SetDCBrushColor都會改變畫刷的顏色,所以,比如你希望繪制藍 色的矩形,在調用Rectangle之前就要調用SetDCBrushColor修改畫刷顏色,然後再畫矩形。我們可以看 看上面代碼的最終效果。

下面,我們做一個人類歷史上最簡單的畫圖程序。

我們為程序提供幾種可選的線條風格 ,通過菜單來選擇,如實線,虛線等,鼠標按下左鍵後開始,鼠標左鍵彈起就完成一條直線的繪制。為 了簡化,我們把相應菜單的ID設置的值與CreatePen中的線型的宏的值一致。

這樣一來,選擇了哪個菜單就直接用這個菜單的ID來創建畫筆,就省去了許多代碼。

在響應WM_CREATE消息時,創建菜單。

case WM_CREATE:     
    {     
        // 創建菜單     
        HMENU menubar = CreateMenu();     
        HMENU menuPop = CreatePopupMenu();     
        AppendMenu(menuPop,MF_STRING,(UINT_PTR)PS_SOLID,L"實線");     
        AppendMenu(menuPop,MF_STRING,(UINT_PTR)PS_DASH,L"虛線");     
        AppendMenu(menuPop,MF_STRING,(UINT_PTR)PS_DOT,L"點線");     
        AppendMenu(menuPop,MF_STRING,(UINT_PTR)PS_DASHDOT,L"點虛線");     
        AppendMenu(menubar, MF_STRING | MF_POPUP, (UINT_PTR)menuPop, L"選擇線型");     
        SetMenu(hwnd, menubar);     
    }     
    return 0;

現在我們來想一下,繪制直線的大概思路。

1、鼠標左鍵按下,記錄線 條的起點。

2、鼠標左鍵彈起時,記錄線條的終點,並畫出整條線。

3、當窗口發生重繪 時,前面畫的所有線條被清除,要希望保留前面畫的線條,就要響應WM_PAINT消息,把所有線條重新畫 一次。

4、由於我們會在窗口上畫出多條線,程序需要定義一個結構體用來保存線條的起點、終 點和所使用的線型。

5、正因為需要保存多條線的數據,故可以把每一條線的相關數據放到一個 vector中。

根據上面的分析,完成程序的代碼如下:

#include <Windows.h>   

  
#include <WindowsX.h>     
#include <vector>     
         
using namespace std;     
         
typedef struct tagData     
{     
    int ptBeginX, ptBeginY;//起點     
    int ptEndX, ptEndY;//終點     
    int penStyle;//畫筆的線型     
} PAINTDATA;     
         
LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);     
         
int WINAPI WinMain(     
    HINSTANCE hThisApp,     
    HINSTANCE hPrevApp,     
    LPSTR lpsCmd,     
    int nShow)     
{     
    WNDCLASS wc = {};     
    wc.hbrBackground = CreateSolidBrush(RGB(0,0,0));     
    wc.hInstance = hThisApp;     
    wc.lpfnWndProc = WindowProc;     
    wc.lpszClassName = L"My";     
    wc.style = CS_HREDRAW | CS_VREDRAW;     
    RegisterClass(&wc);     
    HWND hwnd = CreateWindow(     
        L"My",     
        L"應用程序",     
        WS_OVERLAPPEDWINDOW,     
        50,     
        20,     
        600,     
        480,     
        NULL,     
        NULL,     
        hThisApp,     
        NULL);     
    if(hwnd == NULL)     
        return -1;     
    ShowWindow(hwnd, nShow);     
    UpdateWindow(hwnd);     
    MSG msg;     
    while(GetMessage(&msg,NULL,0,0))     
    {     
        TranslateMessage(&msg);     
        DispatchMessage(&msg);     
    }     
    return 0;     
}     
         
LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)     
{     
    static vector<PAINTDATA> datas;     
    static int penStyle = PS_SOLID;     
    static PAINTDATA *pCurrentData = NULL;//指向當前PAINTDATA的指針     
    switch(msg)     
    {     
    case WM_CREATE:     
        {     
            // 創建菜單     
            HMENU menubar = CreateMenu();     
            HMENU menuPop = CreatePopupMenu();     
            AppendMenu(menuPop,MF_STRING,(UINT_PTR)PS_SOLID,L"實線");     
            AppendMenu(menuPop,MF_STRING,(UINT_PTR)PS_DASH,L"虛線");     
            AppendMenu(menuPop,MF_STRING,(UINT_PTR)PS_DOT,L"點線");     
            AppendMenu(menuPop,MF_STRING,(UINT_PTR)PS_DASHDOT,L"點虛線");     
            AppendMenu(menubar, MF_STRING | MF_POPUP, (UINT_PTR)menuPop, L"選擇線型");     
            SetMenu(hwnd, menubar);     
        }     
        return 0;     
    case WM_COMMAND:     
        {     
            //為選中的菜單加上單選標記     
            HMENU mnbar = GetMenu(hwnd);     
            HMENU hmnPop = GetSubMenu(mnbar, 0);     
            CheckMenuRadioItem(hmnPop, PS_SOLID, PS_DASHDOT, LOWORD(wParam), 

MF_BYCOMMAND);     
            //記錄用戶選擇的線型     
            penStyle = (int)LOWORD(wParam);     
        }     
        return 0;     
    case WM_LBUTTONDOWN:     
        {     
            pCurrentData = new PAINTDATA;     
            //獲取起點     
            pCurrentData ->penStyle = penStyle;     
            pCurrentData->ptBeginX = GET_X_LPARAM(lParam);     
            pCurrentData->ptBeginY = GET_Y_LPARAM(lParam);     
        }     
        return 0;     
    case WM_LBUTTONUP:     
        {     
            if(pCurrentData != NULL)     
            {     
                //獲取終點     
                pCurrentData->ptEndX = GET_X_LPARAM(lParam);     
                pCurrentData->ptEndY = GET_Y_LPARAM(lParam);     
                //畫出線條     
                HDC hdc = GetDC(hwnd);     
                HPEN pen = CreatePen(pCurrentData->penStyle,1,RGB(0,255,0));     
                HPEN oldpen = (HPEN)SelectObject(hdc,pen);     
                MoveToEx(hdc,pCurrentData->ptBeginX,pCurrentData->ptBeginY,NULL);    

 
                LineTo(hdc,pCurrentData->ptEndX,pCurrentData->ptEndY);     
                SelectObject(hdc,oldpen);     
                DeleteObject(pen);     
                ReleaseDC(hwnd,hdc);     
                //把當前數據添加到vector中     
                datas.push_back(*pCurrentData);     
            }     
        }     
        return 0;     
    case WM_PAINT:     
        {     
            PAINTSTRUCT ps;     
            BeginPaint(hwnd,&ps);     
            //將所有線條重新畫一遍     
            vector<PAINTDATA>::const_iterator item;     
            for(item = datas.begin(); item != datas.end(); item++)     
            {     
                HPEN pen = CreatePen(item->penStyle, 1, RGB(0,255,0));     
                SelectObject(ps.hdc, pen);     
                MoveToEx(ps.hdc, item->ptBeginX, item->ptBeginY, NULL);     
                LineTo(ps.hdc, item->ptEndX, item->ptEndY);     
                DeleteObject(pen);     
            }     
            EndPaint(hwnd,&ps);     
        }     
        return 0;     
    case WM_DESTROY:     
        PostQuitMessage(0);     
        return 0;     
    default:     
        return DefWindowProc(hwnd,msg,wParam,lParam);     
    }     
    return 0;     
}

結構體PAINTDATA用來保存每一條線的起點坐標、終點坐標、線型。為了避免在跳出 WindowProc後所有數據被回收,可以使用static關鍵字來聲明變量,這樣這些變量的生命周期就與整個 應用程序相同了。

運行程序後,在菜單中選擇一種線型,然後在窗口上畫線,效果如圖所示。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved