《GDI+系列教程》第9章 —— 模块化的进度条

初始化上一章,我们已经可以和自绘文字框有最基本的交互了。

本章,我们将进一步的,把一个自绘进度条模块化,使其在任何 GUI 上都能使用。

《GDI+系列教程》第9章 —— 模块化的进度条


1.初始化 GDI+

#SingleInstance, Force
#NoEnv
SetBatchLines, -1

; Uncomment if Gdip.ahk is not in your standard library
#Include, Gdip_All.ahk

; 初始化 gdi+
if !pToken := Gdip_Startup()
{
	MsgBox, 48, gdiplus error!, Gdiplus failed to start. Please ensure you have gdiplus on your system
	ExitApp
}
OnExit, ExitGdip

2.创建 GUI 并思考模块化设计

; Before we start there are some design elements we must consider.
; We can either make the script faster. Creating the bitmap 1st and just write the new progress bar onto it every time and updating it on the gui
; and dispose it all at the end/ This will use more RAM
; Or we can create the entire bitmap and write the information to it, display it and then delete it after every occurence
; This will be slower, but will use less RAM and will be modular (can all be put into a function)
; I will go with the 2nd option, but if more speed is a requirement then choose the 1st
; 先讲一下自绘进度条的原理。
; 我们使用 GDI+ 绘制进度条图案,然后把图案显示在 GUI 上的图片控件中,这样就实现了自绘进度条。
; 接着再说一下进度条的设计问题。
; 我们的自绘进度条有3层,最下面是背景层,上面是进度层,最上面是文字。
; 现在有2种方案。
; 1是创建好背景图像后,每次更新进度层和文字即可。
; 最后程序退出时,统一回收资源,这样做速度更快,但将使用更多内存。
; 2是每次更新时,创建完整的背景与进度与文字的图像,再立刻回收资源。
; 这样速度相对更慢,但可以模块化(写成一个函数),同时内存使用更少。
; 本示例选择了第二种方案。
Gui, 1: -DPIScale
; I am first creating a slider, just as a way to change the percentage on the progress bar
Gui, 1: Add, Slider, x10 y10 w400 Range0-100 vPercentage gSlider ToolTip, 50

; The progress bar needs to be added as a picture, as all we are doing is creating a gdi+ bitmap and setting it to this control
; Note we have set the 0xE style for it to accept an hBitmap later and also set a variable in order to reference it (could also use hwnd)
; 我们的自绘进度条原理就是一张不断变化的图片。
; 注意,这里使用了 0xE 选项,这样这个图片控件就能直接接收 hBitmap 格式的图像了。
Gui, 1: Add, Picture, x10 y+30 w400 h100 0xE vProgressBar
Gui, 1: Show, AutoSize, Example 9 - gdi+ Progress bar
; We will set the initial image on the control before showing the gui
; 由于设计上是每次进度条控件更新后,才会跟着画一次自绘进度条,所以一开始需要主动先画一次,不然自绘进度条初始将显示为白板。
gosub, Slider
return

;#######################################################################

; This subroutine is activated every time we move the slider as I used gSlider in the options of the slider
; 这里发挥了控件 g标签 的作用。每次进度条控件发生变化时,都会自动激活到这个子程序中来。
Slider:
	Gui, 1: default
	Gui, 1: Submit, NoHide
	; 注意第5个参数可以不传的,因为函数内部有同样的处理。
	; 第5个参数的意思就是在自绘进度条上面再显示一下当前的进度文字而已。
	Gdip_SetProgress(ProgressBar, Percentage, 0xff0993ea, 0xffbde5ff, Percentage "`%")
return

3.创建可复用的绘制进度条函数

; Gdip_SetProgress(图片控件名, 当前进度, 前景色, 背景色, 文字, 文字选项, 字体)
Gdip_SetProgress(ByRef Variable, Percentage, Foreground, Background=0x00000000, Text="", TextOptions="x0p y15p s60p Center cff000000 r4 Bold", Font="Arial")
{
	; We first want the hwnd (handle to the picture control) so that we know where to put the bitmap we create
	; We also want to width and height (posw and Posh)
	; 获取图片控件的位置信息(x、y、宽、高),以及句柄
	GuiControlGet, Pos, Pos, Variable
	GuiControlGet, hwnd, hwnd, Variable

	; Create 2 brushes, one for the background and one for the foreground. Remember this is in ARGB
	; 创建2支刷子,前景和背景,注意颜色是 ARGB 格式!
	pBrushFront := Gdip_BrushCreateSolid(FoReground), pBrushBack := Gdip_BrushCreateSolid(Background)
	; Create a gdi+ bitmap the width and height that we found the picture control to be
	; We will then get a reference to the graphics of this bitmap
	; We will also set the smoothing mode of the graphics to 4 (Antialias) to make the shapes we use smooth
	; 使用图片控件的宽和高创建一个位图。
	pBitmap := Gdip_CreateBitmap(Posw, Posh), G := Gdip_GraphicsFromImage(pBitmap), Gdip_SetSmoothingMode(G, 4)

	; We will fill the background colour with out background brush
	; x = 0, y = 0, w = Posw, h = Posh
	; 使用矩形画背景。
	Gdip_FillRectangle(G, pBrushBack, 0, 0, Posw, Posh)

	; We will then fill a rounded rectangle with our other brush, starting at x = 4 and y = 4
	; The total width is now Posw-8 as we have slightly indented the actual progress bar
	; The last parameter which is the amount the corners will be rounded by in pixels has been made to be 3 pixels...
	; ...however I have made it so that they are smaller if the percentage is too small as it cannot be rounded by that much
	; 使用圆角矩形画前景。注意前景要比背景小一点,不然就把背景全遮住了。
	Gdip_FillRoundedRectangle(G, pBrushFront, 4, 4, (Posw-8)*(Percentage/100), Posh-8, (Percentage >= 3) ? 3 : Percentage)

	; As mentioned in previous examples, we will provide Gdip_TextToGraphics with the width and height of the graphics
	; We will then write the percentage centred onto the graphics (Look at previous examples to understand all options)
	; I added an optional text parameter at the top of this function, to make it so you could write an indication onto the progress bar
	; such as "Finished!" or whatever, otherwise it will write the percentage to it
	; 写字,没有传这个参数进来的话,则写形如 “50%” 的当前进度值。
	Gdip_TextToGraphics(G, (Text != "") ? Text : Round(Percentage) "`%", TextOptions, Font, Posw, Posh)

	; We then get a gdi bitmap from the gdi+ one we've been working with...
	; 将 pBitmap 格式转换成图片控件可以使用的 hBitmap 格式。
	hBitmap := Gdip_CreateHBITMAPFromBitmap(pBitmap)
	; ... and set it to the hwnd we found for the picture control
	; 将内容更新到图片控件上。
	SetImage(hwnd, hBitmap)

	; We then must delete everything we created
	; So the 2 brushes must be deleted
	; Then we can delete the graphics, our gdi+ bitmap and the gdi bitmap
	; 释放资源。
	Gdip_DeleteBrush(pBrushFront), Gdip_DeleteBrush(pBrushBack)
	Gdip_DeleteGraphics(G), Gdip_DisposeImage(pBitmap), DeleteObject(hBitmap)
	return, 0
}

4.收工善后

GuiClose:
ExitGdip:
	; gdi+ may now be shutdown
	Gdip_Shutdown(pToken)
	ExitApp
return

本章习题:使用模块化进度条,在自己的 GUI 中,让进度在10秒内从0%-100%显示。


全部代码与库文件下载地址:

https://ahk.lanzoux.com/b01nypnuh

密码:

给TA捐赠
共{{data.count}}人
人已捐赠
函数教程

获取Hash函数【gethash()】及其实际应用案例集锦

2021-2-1 12:50:33

教程

《GDI+系列教程》第10章 —— 屏幕放大镜

2021-2-3 11:37:36

4 条回复 A文章作者 M管理员
  1. sunwind

    老哥 加油

  2. AHK中文社区

    我敲了一遍有点问题,后续再好好调调

  3. ddgsa

    谢谢分享

  4. 飞翔

    谢谢分享

个人中心
购物车
优惠劵
有新私信 私信列表
搜索