使用Windows API進行GDI視窗繪圖

龙骑科技發表於2024-05-28

1.概述
在Windows上繪圖方式,跟美術大師繪圖差不多。美術繪畫,首先要具備以下工具:畫板,畫布,畫筆,畫刷。同樣,Windows上也有相關的概念。繪圖裝置DeviceContext(DC),點陣圖Bitmap,畫筆Pen,畫刷brush。他們一一對應。

2.畫板
在Windows中被稱作裝置上下文(Device Context,DC),我習慣稱之為繪圖裝置。但是Windows的“畫板”與美術大師手中的“畫板”不一樣,Windows中的“畫板”實質上是一個工具的集合體,將畫布、畫筆、畫刷、繪畫方式全部綜合管理起來,然後,所有的繪畫操作都將在這上面進行。

1)系統繪圖裝置。系統有預設的繪圖,我們可以直接使用它進行一系列的繪圖操作。

獲取系統繪圖裝置:

HDC GetDC(
 
HWND hWnd // 視窗控制代碼。即指定獲得那個視窗的繪圖裝置。
 
);

如:

HDC hDC = GetDC(g_hWnd);
 
Rectangle(hDC,0,0,100,100);//繪製矩形
 
....

使用完畢後要歸還給視窗:

int ReleaseDC(
 
HWND hWnd, // handle to window
 
HDC hDC // handle to DC
 
);

2)建立畫板。通常我們不直接使用系統畫板,因為系統畫板直接和顯示器關聯,在上面一邊畫,就會一邊顯示到視窗,由於在繪製的時候,中間有時間差(我們可能經過若干次繪製,才繪製完一個地圖),而遊戲程式需要反覆的擦除、重繪,所以常常會造成畫面劇烈閃爍。為了解決這個問題,我們會建立一個輔助畫板,在幕後繪製完畢後,一次性的將它顯示到螢幕上,因為顯示的時間非常快,所以就看不到閃爍。

建立輔助繪圖裝置:

HDC CreateCompatibleDC(
 
HDC hdc // 指向一個已經存在的DC,如果該值傳入0,則系統會建立一個存貯DC。
 
);

存貯DC(輔助繪圖裝置),在建立完畢後,它的大小隻有一個畫素,我們沒辦法直接往他上面直接繪圖,我們還需要往它上面貼一張畫布。

使用完畢後記得要釋放資源:

BOOL DeleteDC(
 
HDC hdc // handle to DC
 
);

例:

HDC memDC = CreateCompatibleDC(0); //建立輔助繪圖裝置
 
SelectObject(memDC,hBitmap); //將畫布貼到繪圖裝置上
 
Rectangle(memDC,x1,y1,x2,y2); //繪製矩形
 
HDC hDC = GetDC(g_hWnd); //獲得系統繪圖裝置
 
copy memDC to hDC //複製到系統裝置上顯示
 
ReleaseDC(g_hWnd,hDC); //歸還系統繪圖裝置
 
DeleteDC(memDC); //釋放輔助繪圖裝置

3.畫布

畫布其實就是點陣圖。點陣圖的作用非常強大,在此我只介紹它的普通用法——充當畫布。其他作用,後面再介紹。

建立掩碼點陣圖(畫布):

HBITMAP CreateCompatibleBitmap(
 
HDC hdc, //指向繪圖裝置,最好是系統的繪圖裝置
 
int nWidth, // 點陣圖寬度
 
int nHeight // 點陣圖高度
 
);

釋放資源:

BOOL DeleteObject(
 
HGDIOBJ hObject // handle to graphic object
 
);

4.畫筆

畫筆就不用解釋了,Windows的畫筆和美術大師的差不多。

建立畫筆:

HPEN CreatePen(
 
int fnPenStyle, // 畫筆風格。直線:PS_SOLID,點線:PS_DOT
 
int nWidth, // 畫筆寬度。決定了畫出來的線條粗細
 
COLORREF crColor // 畫筆顏色
 
);

釋放資源:

BOOL DeleteObject(
 
HGDIOBJ hObject // handle to graphic object
 
);

顏色:可由紅綠藍三種顏色按程度混合起來構成。

如COLORREF cr = RGB(255,0,255),此時cr是粉紅色(紅色+藍色)。COLORREF實際上是無符號長整型的別名,RGB將紅綠藍三個數值整合成一個無符號長整型數。

COLORREF RGB(
 
BYTE byRed, //紅色分量0~255,值越大表面程度越深。
 
BYTE byGreen, // 綠色分量0~255
 
BYTE byBlue // 藍色分量0~255
 
);

5.畫刷

建立畫刷:

HBRUSH CreateSolidBrush(
 
COLORREF crColor // brush color value
 
);

釋放資源:

BOOL DeleteObject(
 
HGDIOBJ hObject // handle to graphic object
 
);

6.繪畫
畫布、畫筆、畫刷建立好之後,要是分別使用API,將它們選入繪圖裝置。當然,繪圖裝置,有自己的預設畫刷和畫筆。

HGDIOBJ SelectObject(
 
HDC hdc, // 直線繪圖裝置
 
HGDIOBJ hgdiobj // 指向GDI物件。就是畫刷、畫筆、點陣圖等。
 
);

返回值是舊有的相關內容。

一些常用繪圖API:
1)繪製矩形。

BOOL Rectangle(
 
HDC hdc, // 繪圖裝置
 
int nLeftRect, // 矩形區域左上角x座標
 
int nTopRect, // 矩形區域左上角y座標
 
int nRightRect, //矩形區域右下角x座標
 
int nBottomRect // 矩形區域右下角y座標
 
);

2)填充區域。用畫刷來填充區域,經常用來擦除整個視窗。

int FillRect(
 
HDC hDC, // 繪圖裝置
 
CONST RECT *lprc, // 矩形區域
 
HBRUSH hbr // 填充畫刷
 
);

區域結構:

typedef struct _RECT {
 
LONG left; //矩形左邊(左上角x座標)
 
LONG top; //矩形頂邊(左上角y座標)
 
LONG right; //矩形右邊(右下角x座標)
 
LONG bottom; //矩形底邊(右下角y座標)
 
} RECT, *PRECT;

獲得視窗客戶區區域:

BOOL GetClientRect(
 
HWND hWnd, // handle to window
 
LPRECT lpRect // client coordinates
 
);

3)繪圖裝置之間的複製。

BOOL BitBlt(
 
HDC hdcDest,//目標繪圖裝置
 
int nXDest, // 目標區域左上角x座標
 
int nYDest, //目標區域左上角y座標
 
int nWidth, // 目標區域寬度
 
int nHeight,// 目標區域高度
 
HDC hdcSrc, // 源繪圖裝置
 
int nXSrc, // 源區域左上角x座標
 
int nYSrc, // 源區域左上角y座標
 
DWORD dwRop // 操作碼。常用SRCCOPY(複製)。
 
);

可以簡單的理解這個API:將源繪圖裝置複製給目標繪圖裝置。從幕後畫布複製給前景畫布。從幕後繪圖裝置複製給顯示器。複製的區域,就是上面指定的。

如:BitBlt(hDC,0,0,g_nWidth,g_nHeight,memDC,0,0,SRCCOPY);


4)其他常用API

文書處理
建立字型:CreateFont,CreatePointFont,SelectObject(.,font)。
顯示文字:Textout,DrawText
設定文字顏色:SetTextColor ,GetTextColor
設定背景:SetBkColor,SetBkMode(設定背景模式,TRANSPARENT為透明)

繪製
點:SetPixel,SetPixelV,GetPixel。
線:MoveToEx-LinTo。
圓:Ellipse
多邊形:Polygon
弧:Arc

點陣圖處理
從檔案載入點陣圖/圖示/游標:LoadImage
從資源載入點陣圖:LoadBitmap
獲得點陣圖資訊:GetObject
繪圖裝置間的複製複製
直接模式:BitBlt
拉伸複製:StretchBlt
透明處理:TranparentBlt,需要加 Msimg32.lib庫。
半透明處理(Alpha混合):AlpaBlend

其他
獲得系統屬性:GetSystemMetrics,一些很重要的資訊。
獲得滑鼠螢幕座標:GetCursorPos,需使用座標轉換轉換為視窗座標
座標轉換:ClientToScreen,ScreenToClient
獲得鍵盤鍵狀態:GetAsyncKeyState
獲得整個鍵盤資訊:GetKeyboardState

訊息框:MessageBox

一個完整的程式碼示例:

#include "app.h"
 
 
 
int g_nWidth = 600;//視窗寬度
 
int g_nHeight = 480;//視窗高度
 
 
 
void init()//遊戲初始化
 
{
 
}
 
 
 
void update()//邏輯更新
 
{
 
}
 
 
 
void render()//畫面渲染
 
{
 
HDC hDC = GetDC(getHWnd()); //獲得系統繪圖裝置
 
 
 
HDC memDC = CreateCompatibleDC(0); //建立輔助繪圖裝置
 
 
 
HBITMAP bmpBack = CreateCompatibleBitmap(hDC,g_nWidth,g_nHeight);//建立掩碼點陣圖(畫布)
 
SelectObject(memDC,bmpBack); //將畫布貼到繪圖裝置上
 
 
 
HPEN penBack = CreatePen(PS_SOLID,1,RGB(255,0,255));//建立畫筆
 
SelectObject(memDC,penBack); //將畫筆選到繪圖裝置上
 
 
 
HBRUSH brushBack = CreateSolidBrush(RGB(255,255,255));//建立畫刷
 
SelectObject(memDC,brushBack); //將畫刷選到繪圖裝置上
 
 
 
//擦除背景
 
RECT rcClient;//區域結構
 
GetClientRect(getHWnd(),&rcClient);//獲得客戶區域
 
HBRUSH brushTemp = (HBRUSH)GetStockObject(WHITE_BRUSH);//獲得庫存物體,白色畫刷。
 
FillRect(memDC,&rcClient,brushTemp);//填充客戶區域。
 
//
 
HBRUSH brushObj = CreateSolidBrush(RGB(0,255,0));//建立物體畫刷
 
//繪製維網格,矩形畫法。
 
int dw = 30;
 
int rows = g_nHeight/dw;
 
int cols = g_nWidth/dw;
 
for (int r=0; r<rows; ++ r)
 
{
 
for (int c=0; c<cols; ++c)
 
{
 
if (r == c)
 
{
 
SelectObject(memDC,brushObj);
 
}
 
else
 
{
 
SelectObject(memDC,brushBack);
 
}
 
Rectangle(memDC,c*dw,r*dw,(c+1)*dw,(r+1)*dw);
 
}
 
}
 
 
 
DeleteObject(brushObj);
 
//
 
BitBlt(hDC,0,0,g_nWidth,g_nHeight,memDC,0,0,SRCCOPY);//複製到系統裝置上顯示
 
DeleteObject(penBack); //釋放畫筆資源
 
DeleteObject(brushBack);//釋放畫刷資源
 
DeleteObject(bmpBack); //釋放點陣圖資源
 
DeleteDC(memDC); //釋放輔助繪圖裝置
 
ReleaseDC(getHWnd(),hDC); //歸還系統繪圖裝置
 
Sleep(1);
 
}
 
 
 
void clear()//資源釋放
 
{
 
}
 
 
 
 
 
//主函式
 
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE , LPSTR , int )
 
{
 
if(!initApp(hInstance,L"貪吃蛇遊戲",g_nWidth,g_nHeight))
 
{
 
return 0;
 
}
 
 
 
//初始化遊戲
 
init();
 
 
 
//遊戲迴圈
 
mainLoop();
 
 
 
//釋放資源
 
clear();
 
 
 
return 0;
 
}

原文地址:https://blog.csdn.net/celte/article/details/10243309

原文地址:http://blog.csdn.net/you_lan_hai/article/details/6911497

相關文章