電腦屏幕上所有能看到的,全是電腦繪畫的結果,我們寫的軟件,要么系統負責繪畫,要么就自己用代碼繪畫。
用電腦繪畫(編程),不管你用什么編程語言,到最后都是用API繪畫,我們可以拋開編程語言本身,直接使用API繪畫,會效率更高、功能更豐富。
繪畫,不管現實中的,還是電腦里的編程其實很簡單的事,至于畫的漂亮與否,就看藝術天賦和功力了,不扯作品,這里扯會操作。
現實中,拿張紙,找個筆,就可以在那里瞎畫,其實電腦里編程,也是如此簡單,定義個紙和筆,打打鍵盤,就可以畫出來了。
編程繪圖,微軟起了個名詞加:GDI ,后來出了個增加版叫 GDI+ ,名稱是什么不重要,重要的是知道這個名即可。
當然還有個 3D繪圖的,那個不是本教程之內。
為了方便使用,為 FreeBasic語言封裝了類,可以進勇芳編程群里下載例題,其它語言可以參考下面教程,自己也能寫出來。
GDI 和GDI+ 非常豐富,本類只是封裝了最常用的部分,可以自己擴建為無限的可能。

以下是我膚淺的理解和俗話表述,只為編程新手入門,若有不對的地方,敬請高手們批評指正,避免帶新手走了彎路。
一、基礎概念(必須了解,非常重要,理解后,后面操作就不難了)
在現實里繪畫,我們需要 紙、筆,還需要涂顏色的刷子,遇到字,可以用印章印
在編程里,和現實一樣,我們同樣要 紙、筆、刷、字 ,所不同的是,編程里只是用變量來表示
1,紙:或稱畫板,可以是電腦里的桌面、某個軟件窗口、某個窗口里的控件,想畫那里,就變量設那里
Dim nDC as hDC '設置畫板變量,類型 hDC 就是目標紙張或叫畫板
nDC=GetDC(0) '直接把桌面當畫板,就畫在桌面上了,可以用來截圖,要是畫上內容,操作系統在畫桌面,會被覆蓋掉。
nDC=GetDC(窗口或控件句柄) '在某個窗口或控件里畫畫
......畫畫代碼
ReleaseDC 窗口或控件句柄,nDC ‘銷毀畫板,用后必須銷毀,在編程里,有創建,必須有銷毀,不然會消耗大量系統資源,輕則占內存大運行慢,重則軟件崩潰’
2,筆、刷、字(GDI 已經默認分配,GDI+ 則必須創建)

3,圖片 ,這也是必須要有的,圖片可以從文件里或軟件資源里讀取,然后貼上去。
二、 準備工作(廢話不說,直接上代碼)
1,臨時的直接畫畫(會被操作系統刷新掉,因為系統也在畫,被其它窗口覆蓋后移開,系統就開始畫了)
Dim nDC as hDC '準備畫板
Dim tFont As HFONT '準備字
Dim nPen As HPEN '準備筆
Dim nBrush As HBRUSH '準備刷子
nDC=GetDC(窗口或控件句柄) '在某個窗口或控件里畫畫
.........一大批畫畫
ReleaseDC 窗口或控件句柄,nDC ‘用后一定要銷毀’
If tFont Then DeleteObject tFont
If nPen Then DeleteObject nPen '畫筆
If nBrush Then DeleteObject nBrush
2,永久性畫畫(窗口自繪或控件自繪)
Function FORM1_WM_PAINT ( .... 這里是由操作系統,通知窗口,要重新畫畫了。
Dim nDC as hDC '準備畫板
Dim tFont As HFONT '準備字
Dim nPen As HPEN '準備筆
Dim nBrush As HBRUSH '準備刷子
Dim ps As PAINTSTRUCT '繪畫范圍
nDC = BeginPaint(系統通知來的窗口或控件句柄, @ps) '只有在WM_PAINT使用,比 GetDC 繪圖效率高的多
.........一大批畫畫
EndPaint(窗口或控件句柄,nDC) '完成繪圖并且銷毀句柄
If tFont Then DeleteObject tFont
If nPen Then DeleteObject nPen '畫筆
If nBrush Then DeleteObject nBrush
Function = True '返回允許,告訴操作系統,這個我自己畫了,不需要系統來畫。
End Function
3,緩存加速技術(可選的)每一句繪圖命令,將直接輸出到屏幕,內容多了就造成繪畫緩慢,我們需要加速,執行完全部再輸出到屏幕。
不用緩存加速,繪畫內容多點,就會卡的,因此,不要嫌棄麻煩,盡量使用這技術
{這里是GDI的準備代碼}來自上面的代碼,就不重復寫了,那樣比較亂
Dim rc As Rect,m_nWidth As Long,m_nHeight As Long,m_hBmp As HBITMAP,m_Dc As hDC,m_hOldBmp As HBITMAP '聲明必要變量
GetClientRect(窗口或控件句柄, @rc) ‘獲取窗口的矩形’
m_nWidth = (rc.Right - rc.Left) + 1 ‘獲取窗口的高度寬度,需要+1’
m_nHeight = (rc.Bottom - rc.Top) + 1
' // 創建一個兼容的位圖
m_hBmp = CreateCompatibleBitmap(m_nDC, m_nWidth, m_nHeight)
' // 創建兼容的設備上下文
m_Dc = CreateCompatibleDC(m_nDC)
' // 將位圖選擇到兼容的設備上下文中
If m_Dc Then m_hOldBmp = SelectObject(m_Dc, m_hBmp)
.........一大批畫畫,畫到 m_DC 里,這是緩存
BitBlt nDC,0,0,m_nWidth,m_nHeight,m_Dc,0,0,SrcCopy '將內存DC,輸出到窗口,至此輸出到屏幕,讓我們看到了
' // 恢復原始位圖
SelectObject(m_Dc, m_hOldBmp)
' // 銷毀位圖和內存設備上下文
DeleteObject m_hBmp
DeleteDC m_Dc
{這里是GDI的清理代碼}
4,GDI+ 初始化和準備工作(GDI+ 可以選,沒用到,就可以不寫,要用就寫了。)
GDI+ 比GDI最大的好處是反鋸齒,讓畫畫更好看舒服,但速度就變慢了。還有支持更多格式的圖片文件和漸變填色,一般盡量用 GDI ,特殊需要再用 GDI+
GDI+ 初始化(VisualFreeBasic 在工程屬性里選擇啟用GDI+ ,不需要寫代碼)
======寫在軟件的最開始處========== VisualFreeBasic 不需要寫這些代碼
Dim gdipToken As ULONG_PTR
Dim gdipsi As GdiplusStartupInput
gdipsi.GdiplusVersion = 1
GdiplusStartup( @gdipToken, @gdipsi, Null ) ‘通知系統,軟件要用GDI+’
======寫在關閉軟件處的代碼==========
GdiplusShutdown( gdipToken ) ‘關閉GDI+庫,必須清理,避免浪費系統資源’
準備工作
{這里是GDI的準備代碼}
{這里是緩存加速準備代碼}
nGpDC As GpGraphics Ptr 'GDI+ 的DC
nGpPen As GpPen Ptr 'GDI+ 筆
nGpBrush As GpBrush Ptr 'GDI+ 刷
nGpimage As GpImage Ptr 'GDI+ 位圖,用來畫圖
GdipCreateFromHDC(m_Dc, @nGpDC) ‘把GDI+ 對應為 GDI的DC,這樣畫的內容就立即到 那里了,這里是用 緩存DC’
GdipSetSmoothingMode nGpDC,SmoothingModeAntiAlias ‘設置GDI+為消除鋸齒模式,用GDI+就是看中反鋸齒’
.........一大批畫畫,畫到GDI+ 或 GDI 里
If nGpDC Then GdipDeleteGraphics(nGpDC) '下面是清理工作
If nGpPen Then GdipDeletePen nGpPen
If nGpBrush Then GdipDeleteBrush nGpBrush 'GDI+ 刷
If nGpimage Then GdipDisposeImage nGpimage
{這里是緩存加速清理代碼}
{這里是GDI的清理代碼}
5,使用類,準備和清理工作,比較煩,但必須要寫,可以建立個類,就方便了,以上所有的,只需要一句(包括GDI+)
FB的類在勇芳編程群里下載,其它語言需要你自己創建。
臨時畫畫
Dim gg As yGDI = 窗口或控件句柄
永久畫畫(是指 WM_PAINT 消息里,假如臨時畫畫用這個,是畫不出來的)
Dim gg As yGDI = yGDI(窗口或控件句柄,底色,True)
準備工作做好了,我們就開始實戰吧,
請看 實戰GDI 篇 和 GDI+實戰篇
API畫畫流程:
{這里是GDI的準備代碼}
{這里是緩存加速準備代碼}
{這里是GDI+準備代碼}
...這里才是我們自己寫的代碼,要畫的內容....
{這里是GDI+清理代碼}
{這里是緩存加速清理代碼}
{這里是GDI的清理代碼}