win32 API程式設計之GDI繪圖

肆空界發表於2024-12-06

一、GDI簡介

1)什麼是裝置上下文

2)裝置上下文型別

3)常見的GDI物件

4)windows座標系

5)GDI繪圖步驟

二、獲取DC的3種方法

1)獲取DC的3種方法

2)PAINTSTRUCT結構

3)BeginPaint函式

4)EndPaint函式

5)GetDC函式

6)GetWindowDC函式

7)三種方式的區別

8)程式碼例項

複製程式碼
#include<windows.h> 


//自定義的視窗過程
LRESULT  CALLBACK    MyWindowProc(HWND hWnd, UINT Msg,
    WPARAM wParam, LPARAM lParam)
{
    switch (Msg)
    {
    case WM_DESTROY:
        PostQuitMessage(0);//可以使GetMessage返回0    
        return 0;

    case WM_PAINT:
    { 
        //1.使用BeginPaint,它能將無效區域變成有效(如果存在無效區域,系統會一直髮送WM_PAINT)
        /*PAINTSTRUCT  ps;
        HDC  hdc = BeginPaint(hWnd, &ps);
        TextOut(hdc, 0, 0, L"你好啊!", lstrlen(L"你好啊!"));
        EndPaint(hWnd, &ps);*/

        //2.使用GetDC獲取客戶區DC,它並不能將無效區域變成有效,所以WM_PAINT一直髮送,文字一直閃爍
        /*
        HDC  hdc = GetDC(hWnd);
        TextOut(hdc, 0, 0, L"你好啊!", lstrlen(L"你好啊!"));
        ReleaseDC(hWnd, hdc);
        //return 0; //去掉之後交給預設DefWindowProc處理WM_PAINT訊息,會呼叫BeginPaint,EndPaint
        */ 

    }
    break;

    case WM_NCPAINT:
    {
        //3.獲取整個視窗的DC,包括標題欄,工具條等
        HDC  hdc = GetWindowDC(hWnd);
        RECT  r = {0,0,400,20};
        HBRUSH  brh = CreateSolidBrush(RGB(255, 0, 0));
        FillRect(hdc, &r, brh);
        DeleteObject(brh);
        ReleaseDC(hWnd, hdc);//釋放掉DC
        return  true;


    }break;

    }

    return DefWindowProc(hWnd, Msg, wParam, lParam);
}


int  WINAPI   WinMain(HINSTANCE  hInstance, HINSTANCE  hPrevInstance,
    LPSTR lpCmdLine, int  nShowCmd)
{

    //1.註冊視窗類
    WNDCLASS  wnd;
    wnd.cbClsExtra = 0;
    wnd.cbWndExtra = 0;
    wnd.hbrBackground = (HBRUSH)(GetStockObject(GRAY_BRUSH));//背景色
    wnd.hCursor = LoadCursor(NULL, IDC_ARROW);//游標
    wnd.hIcon = LoadIcon(NULL, IDI_APPLICATION);//圖示
                                                //wnd.lpfnWndProc = DefWindowProc;//預設視窗過程函式,用於處理訊息
    wnd.lpfnWndProc = MyWindowProc;//自定義的視窗過程函式
    wnd.lpszClassName = L"MrHuang";//視窗類名
    wnd.lpszMenuName = NULL;//選單資源名稱
    wnd.style = CS_HREDRAW | CS_DBLCLKS;//視窗類、樣式
    wnd.hInstance = hInstance;//例項控制代碼
    RegisterClass(&wnd);

    //建立視窗(返回之前傳送WM_CREATE)
    HWND    hWnd = CreateWindow(L"MrHuang", L"第一個視窗程式",
        WS_OVERLAPPEDWINDOW, 100, 100, 400, 400, NULL, NULL, hInstance, NULL);

    //顯示視窗
    ShowWindow(hWnd, nShowCmd);
    //更新視窗(傳送WM_PAINT)
    UpdateWindow(hWnd);

    //訊息迴圈(收到WM_QUIT訊息退出)
    MSG  msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);//翻譯訊息
        DispatchMessage(&msg);//分發訊息到視窗過程
    }
}
複製程式碼

三、繪圖函式

1)建立畫筆

2)選擇一個物件到資料上下文

3)畫直線

4)畫矩形

5)建立畫刷

6)DeleteObject函式

7)GetStockObject函式

8)畫橢圓

9)畫餅圖

10)寫入字串

11)SetBkColor函式

12)SetBkMode函式

13)DrawText函式

14)SetTextAlign函式

15)程式碼例項

①繪製直線、矩形、橢圓、餅圖

複製程式碼
#include<windows.h> 


//自定義的視窗過程
LRESULT  CALLBACK    MyWindowProc(HWND hWnd, UINT Msg,
    WPARAM wParam, LPARAM lParam)
{
    switch (Msg)
    {
    case WM_DESTROY:
        PostQuitMessage(0);//可以使GetMessage返回0    
        return 0;

    case WM_PAINT: 
    {
        PAINTSTRUCT ps;
        //獲取裝置上下文控制代碼
        HDC   hdc = BeginPaint(hWnd, &ps);
 
        //建立畫筆
        HPEN  hPen = CreatePen(PS_DASHDOT, 1, RGB(255, 0, 0));
        //將筆選入到裝置上下文(使用這支筆)
        SelectObject(hdc, hPen);

        //1.畫直線(兩個點)
        MoveToEx(hdc, 100, 100, NULL);
        LineTo(hdc, 200, 100);

        //建立畫刷
        HBRUSH hBsh = CreateSolidBrush(RGB(0, 255, 0));
        //將畫刷選入到裝置上下文(使用這支畫刷)
        SelectObject(hdc, hBsh);
         
        //2.畫矩形(正方形)
        Rectangle(hdc, 200, 200, 400, 400);


        //獲取透明畫刷
        HGDIOBJ hBsh2  =GetStockObject(NULL_BRUSH);
        SelectObject(hdc, hBsh2);
        Rectangle(hdc,  100, 100, 200, 150);

        //3.畫橢圓(圓形)
        Ellipse(hdc, 200, 200, 400, 400);
        Ellipse(hdc, 100, 100, 200, 150);


        //4.畫餅圖 
/*            
        //餅圖產生的步驟分解
        Ellipse(hdc, 500, 100, 800, 400); 
         //從圓心到第一個點的連線
         MoveToEx(hdc, 650, 250, NULL);
         LineTo(hdc,1000, 300);  
         //從圓心到第二個點的連線
         MoveToEx(hdc, 650, 250, NULL);
         LineTo(hdc, 400, 400);
 */        
         Pie(hdc, 500, 100, 800, 400, 1000, 300,400, 400);


        //刪除GDI物件
        DeleteObject(hPen);
        DeleteObject(hBsh);

        EndPaint(hWnd, &ps);
    }
    break;

    }

    return DefWindowProc(hWnd, Msg, wParam, lParam);
}


int  WINAPI   WinMain(HINSTANCE  hInstance, HINSTANCE  hPrevInstance,
    LPSTR lpCmdLine, int  nShowCmd)
{

    //1.註冊視窗類
    WNDCLASS  wnd;
    wnd.cbClsExtra = 0;
    wnd.cbWndExtra = 0;
    wnd.hbrBackground = (HBRUSH)(GetStockObject(GRAY_BRUSH));//背景色
    wnd.hCursor = LoadCursor(NULL, IDC_ARROW);//游標
    wnd.hIcon = LoadIcon(NULL, IDI_APPLICATION);//圖示
                                                //wnd.lpfnWndProc = DefWindowProc;//預設視窗過程函式,用於處理訊息
    wnd.lpfnWndProc = MyWindowProc;//自定義的視窗過程函式
    wnd.lpszClassName = L"MrHuang";//視窗類名
    wnd.lpszMenuName = NULL;//選單資源名稱
    wnd.style = CS_HREDRAW | CS_DBLCLKS;//視窗類、樣式
    wnd.hInstance = hInstance;//例項控制代碼
    RegisterClass(&wnd);

    //建立視窗(返回之前傳送WM_CREATE)
    HWND    hWnd = CreateWindow(L"MrHuang", L"第一個視窗程式",
        WS_OVERLAPPEDWINDOW, 100, 100, 1000, 700, NULL, NULL, hInstance, NULL);

    //顯示視窗
    ShowWindow(hWnd, nShowCmd);
    //更新視窗(傳送WM_PAINT)
    UpdateWindow(hWnd);

    //訊息迴圈(收到WM_QUIT訊息退出)
    MSG  msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);//翻譯訊息
        DispatchMessage(&msg);//分發訊息到視窗過程
    }
}
複製程式碼

②寫入字串

複製程式碼
#include<windows.h> 


//自定義的視窗過程
LRESULT  CALLBACK    MyWindowProc(HWND hWnd, UINT Msg,
    WPARAM wParam, LPARAM lParam)
{
    switch (Msg)
    {
    case WM_DESTROY:
        PostQuitMessage(0);//可以使GetMessage返回0    
        return 0;

    case WM_PAINT:
    {
        PAINTSTRUCT ps;
        //獲取裝置上下文控制代碼
        HDC   hdc = BeginPaint(hWnd, &ps);

        //改變文字的背景色
        SetBkColor(hdc, RGB(255, 0, 0));
        //設定文字背景模式 
        SetBkMode(hdc, TRANSPARENT);//透明

        //設定文字的顏色
        SetTextColor(hdc, RGB(255, 0, 0));


        //設定文字的參考點
        SetTextAlign(hdc, TA_TOP);

        //1.介面上畫文字
        TextOut(hdc,250, 200, L"你好啊,這是畫的文字!", lstrlen(L"你好啊,這是畫的文字!"));

        //2.在矩形範圍中畫文字
        RECT  r = {250,400,300,500};
        Rectangle(hdc, r.left, r.top, r.right, r.bottom);
        DrawText(hdc, L"你好啊,這是畫的文字!", lstrlen(L"你好啊,這是畫的文字!")
            , &r,  DT_BOTTOM|DT_SINGLELINE);




        EndPaint(hWnd, &ps);
    }
    break;

    }

    return DefWindowProc(hWnd, Msg, wParam, lParam);
}


int  WINAPI   WinMain(HINSTANCE  hInstance, HINSTANCE  hPrevInstance,
    LPSTR lpCmdLine, int  nShowCmd)
{

    //1.註冊視窗類
    WNDCLASS  wnd;
    wnd.cbClsExtra = 0;
    wnd.cbWndExtra = 0;
    wnd.hbrBackground = (HBRUSH)(GetStockObject(GRAY_BRUSH));//背景色
    wnd.hCursor = LoadCursor(NULL, IDC_ARROW);//游標
    wnd.hIcon = LoadIcon(NULL, IDI_APPLICATION);//圖示
                                                //wnd.lpfnWndProc = DefWindowProc;//預設視窗過程函式,用於處理訊息
    wnd.lpfnWndProc = MyWindowProc;//自定義的視窗過程函式
    wnd.lpszClassName = L"MrHuang";//視窗類名
    wnd.lpszMenuName = NULL;//選單資源名稱
    wnd.style = CS_HREDRAW | CS_DBLCLKS;//視窗類、樣式
    wnd.hInstance = hInstance;//例項控制代碼
    RegisterClass(&wnd);

    //建立視窗(返回之前傳送WM_CREATE)
    HWND    hWnd = CreateWindow(L"MrHuang", L"第一個視窗程式",
        WS_OVERLAPPEDWINDOW, 100, 100, 1000, 700, NULL, NULL, hInstance, NULL);

    //顯示視窗
    ShowWindow(hWnd, nShowCmd);
    //更新視窗(傳送WM_PAINT)
    UpdateWindow(hWnd);

    //訊息迴圈(收到WM_QUIT訊息退出)
    MSG  msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);//翻譯訊息
        DispatchMessage(&msg);//分發訊息到視窗過程
    }
}
複製程式碼

四、雙緩衝繪製技術

1)什麼是雙緩衝繪製技術

2)步驟

3)CreateCompatiableDC函式

4)CreateCompatiableBitmap函式

5)BitBlt函式

6)StretchBlt函式

7)程式碼例項

複製程式碼
#include<windows.h>
#include<CommCtrl.h> 


//自定義的視窗過程
LRESULT  CALLBACK    MyWindowProc(HWND hWnd, UINT Msg,
    WPARAM wParam, LPARAM lParam)
{
    switch (Msg)
    {
    case WM_DESTROY:
        PostQuitMessage(0);//可以使GetMessage返回0    
        return 0;

    case WM_PAINT:
    {
        PAINTSTRUCT ps;
        HDC   hdc = BeginPaint(hWnd, &ps);
 
         //1.建立相容記憶體DC,此時它的大小時1X1,很小,不能繪製
        HDC  hMemDC=CreateCompatibleDC(hdc);

        //2.建立相容點陣圖,提供繪畫區域
        HBITMAP hMemBmp = CreateCompatibleBitmap(hdc, 100, 100);

        //3.把相容點陣圖選到相容記憶體DC中,此刻DC的大小與點陣圖一致,可以繪製
        SelectObject(hMemDC, hMemBmp);

        //4.在相容記憶體DC上進行繪圖操作
        SetTextColor(hMemDC, RGB(255, 0, 0));
        TextOut(hMemDC, 0, 0, L"雙緩衝技術繪製!", lstrlen(L"雙緩衝技術繪製!")); 
        Rectangle(hMemDC, 30, 30, 80, 80);

        //5.把記憶體DC中的影像一次性畫到視窗DC上
         //不拉伸
         BitBlt(hdc, 0, 0, 100, 100, hMemDC, 0, 0, SRCCOPY);
        
         //拉伸(目標矩形大於源矩形)
         StretchBlt(hdc, 0, 0, 400, 400, hMemDC, 0, 0,100,100, SRCCOPY);
         //壓縮(目標矩形小於源矩形)
         StretchBlt(hdc, 0, 0, 50, 50, hMemDC, 0, 0, 100, 100, SRCCOPY);


         //釋放資源
         DeleteDC(hMemDC);
         DeleteObject(hMemBmp);


        EndPaint(hWnd, &ps);
    }
    break;

    }

    return DefWindowProc(hWnd, Msg, wParam, lParam);
}


int  WINAPI   WinMain(HINSTANCE  hInstance, HINSTANCE  hPrevInstance,
    LPSTR lpCmdLine, int  nShowCmd)
{

    //1.註冊視窗類
    WNDCLASS  wnd;
    wnd.cbClsExtra = 0;
    wnd.cbWndExtra = 0;
    wnd.hbrBackground = (HBRUSH)(GetStockObject(GRAY_BRUSH));//背景色
    wnd.hCursor = LoadCursor(NULL, IDC_ARROW);//游標
    wnd.hIcon = LoadIcon(NULL, IDI_APPLICATION);//圖示
                                                //wnd.lpfnWndProc = DefWindowProc;//預設視窗過程函式,用於處理訊息
    wnd.lpfnWndProc = MyWindowProc;//自定義的視窗過程函式
    wnd.lpszClassName = L"MrHuang";//視窗類名
    wnd.lpszMenuName = NULL;//選單資源名稱
    wnd.style = CS_HREDRAW | CS_DBLCLKS;//視窗類、樣式
    wnd.hInstance = hInstance;//例項控制代碼
    RegisterClass(&wnd);

    //建立視窗(返回之前傳送WM_CREATE)
    HWND    hWnd = CreateWindow(L"MrHuang", L"第一個視窗程式",
        WS_OVERLAPPEDWINDOW, 100, 100, 400, 400, NULL, NULL, hInstance, NULL);

    //顯示視窗
    ShowWindow(hWnd, nShowCmd);
    //更新視窗(傳送WM_PAINT)
    UpdateWindow(hWnd);

    //訊息迴圈(收到WM_QUIT訊息退出)
    MSG  msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);//翻譯訊息
        DispatchMessage(&msg);//分發訊息到視窗過程
    }
}
複製程式碼

五、繪製點陣圖

1)什麼是點陣圖

2)點陣圖繪製的步驟

3)LoadImage函式

4)SetStrechBltMode函式

5)程式碼例項

複製程式碼
#include<windows.h>
#include<CommCtrl.h> 


//自定義的視窗過程
LRESULT  CALLBACK    MyWindowProc(HWND hWnd, UINT Msg,
    WPARAM wParam, LPARAM lParam)
{
    switch (Msg)
    {
    case WM_DESTROY:
        PostQuitMessage(0);//可以使GetMessage返回0    
        return 0;

    case WM_PAINT:
    {
        PAINTSTRUCT ps;
        HDC   hdc = BeginPaint(hWnd, &ps);

        //1.建立記憶體相容DC(1px  X  1px)
        HDC  hMemDC = CreateCompatibleDC(hdc);

        //2.載入點陣圖資源
        HBITMAP hBmp= (HBITMAP)LoadImage(NULL, L"bg.bmp", IMAGE_BITMAP, 800, 800, LR_LOADFROMFILE);

        //3.把點陣圖選入到相容記憶體DC
        SelectObject(hMemDC, hBmp);

        //新增水印
        TextOut(hMemDC, 100, 100, L"亂塗亂畫", lstrlen(L"亂塗亂畫"));
         
        //設定影像拉伸模式
        //SetStretchBltMode(hdc, COLORONCOLOR);//刪除多餘畫素
        SetStretchBltMode(hdc, HALFTONE); 

        //4.將相容DC中的影像一次性複製到視窗DC上
         //BitBlt(hdc, 0, 0, 800, 800, hMemDC, 0, 0, SRCCOPY);
        //完整顯示
         StretchBlt(hdc, 0, 0, 400, 400, hMemDC, 0, 0, 800,800,SRCCOPY);

        //5.釋放DC與點陣圖資源
        DeleteObject(hBmp);
        DeleteDC(hMemDC);
      
        EndPaint(hWnd, &ps);
    }
    break;

    }

    return DefWindowProc(hWnd, Msg, wParam, lParam);
}


int  WINAPI   WinMain(HINSTANCE  hInstance, HINSTANCE  hPrevInstance,
    LPSTR lpCmdLine, int  nShowCmd)
{

    //1.註冊視窗類
    WNDCLASS  wnd;
    wnd.cbClsExtra = 0;
    wnd.cbWndExtra = 0;
    wnd.hbrBackground = (HBRUSH)(GetStockObject(GRAY_BRUSH));//背景色
    wnd.hCursor = LoadCursor(NULL, IDC_ARROW);//游標
    wnd.hIcon = LoadIcon(NULL, IDI_APPLICATION);//圖示
                                                //wnd.lpfnWndProc = DefWindowProc;//預設視窗過程函式,用於處理訊息
    wnd.lpfnWndProc = MyWindowProc;//自定義的視窗過程函式
    wnd.lpszClassName = L"MrHuang";//視窗類名
    wnd.lpszMenuName = NULL;//選單資源名稱
    wnd.style = CS_HREDRAW | CS_DBLCLKS;//視窗類、樣式
    wnd.hInstance = hInstance;//例項控制代碼
    RegisterClass(&wnd);

    //建立視窗(返回之前傳送WM_CREATE)
    HWND    hWnd = CreateWindow(L"MrHuang", L"第一個視窗程式",
        WS_OVERLAPPEDWINDOW, 100, 100, 400, 400, NULL, NULL, hInstance, NULL);

    //顯示視窗
    ShowWindow(hWnd, nShowCmd);
    //更新視窗(傳送WM_PAINT)
    UpdateWindow(hWnd);

    //訊息迴圈(收到WM_QUIT訊息退出)
    MSG  msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);//翻譯訊息
        DispatchMessage(&msg);//分發訊息到視窗過程
    }
}
複製程式碼

轉載 >>>>>>>win32 API程式設計之GDI繪圖 - ☞@_@ - 部落格園

相關文章