电脑屏幕上所有能看到的,全是电脑绘画的结果,我们写的软件,要么系统负责绘画,要么就自己用代码绘画。
用电脑绘画(编程),不管你用什么编程语言,到最后都是用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的清理代码}