结合之前文章中的例子,我们这次来用代码绘制一个图形,然后显示在用Sciter制作的GUI图形界面中,并且让它自动旋转。
下面的例子中的信息量很大,除了之前的使用gg包进行代码绘图,还演示了纯用Gox代码来操控HTML中的DOM元素(完全不使用Sciter中的TiScript),包括手动创建元素、选择元素和设置其属性等,并通过修改图片标签的transform样式属性,结合Go语言中的协程(类似线程)实现图形不断旋转的效果。
先来看看最终实现的效果:
准备要做的界面就是这样的,简简单单,最上面是一个div,其中一个span显示红字,下面就是一个img标签装载的图形。程序运行后,图形将以中心为轴每个1秒中顺时针旋转45度。
下面就是实现该效果的完整代码:
// 设置image/color包的简称
// github.com/fogleman/gg包已经默认简称gg
color = image_color
// 建立imagetk包的引用,注意该包的用法比较特殊
itk = imagetk.NewImageTK()
// 建立一个绘图环境,图片大小为 600×400 像素
contextT = gg.NewContext(600, 400)
// 用十六进制方式设置当前颜色
contextT.SetHexColor("FFFFFF")
// 用当前颜色来清空整个图片
contextT.Clear()
// 设置线宽为 2 个像素
contextT.SetLineWidth(2)
// 设置RGB颜色,每种颜色的数值范围是 0.0 - 1.0
contextT.SetRGB(0.0, 0.0, 1.0)
// 画一个圆,以坐标为 (200, 200) 的点为圆心,半径为 50像素
contextT.DrawCircle(250, 250, 60)
// 真正进行线条绘制,并且保留绘图路径以便后面填充颜色
contextT.StrokePreserve()
// 创建一个渐变色填充方案 gradientT
// 是两点之间的圆环式渐变色
gradientT = gg.NewRadialGradient(250, 250, 0, 250, 250, 80)
// 创建一个颜色的基本方法
colorT = new(color.RGBA)
colorT.R = uint8(0)
colorT.G = uint8(0)
colorT.B = uint8(0)
colorT.A = uint8(255)
gradientT.AddColorStop(0, colorT)
// 注意创建颜色的快捷方法
gradientT.AddColorStop(1, itk.NewRGBA(0, 0, 255, 255))
// 设置用渐变色 gradientT 填充
contextT.SetFillStyle(gradientT)
// 真正进行填充,并清除绘画路径,因为后面已经不需要了
contextT.Fill()
// 开始用填充的方式绘制一个矩形
// 用RGBA色彩体系设置当前颜色
// 用 0 - 255 的数值范围表示颜色和透明度
// 设置一定的透明度以便显示出被覆盖住的图形(圆形)
contextT.SetRGBA255(0, 255, 0, 180)
// 绘制一个左上角点坐标为 (300, 200),宽 100,高 100的矩形
contextT.DrawRectangle(300, 200, 100, 100)
// 仅填充颜色不绘制边线
contextT.Fill()
// 开始用路径法画一个三角形
// 用十六进制字符串设置颜色
// 可以加上前面的“#”号,也可以后面加上一个字节表示透明度
contextT.SetHexColor("#FF000099")
// 将虚拟的画笔移动到坐标为 (300, 120) 的点
contextT.MoveTo(300, 120)
// 从当前点绘制一条线到坐标为 (240, 230)的点为止
// 当前点将随之移动到 (240, 230)
contextT.LineTo(240, 230)
// 继续绘制一条直线到 (360, 230)
contextT.LineTo(360, 230)
// 继续绘制一条直线到 (300, 120)
contextT.LineTo(300, 120)
// 创建一个新的线性渐变色
gradientT = gg.NewLinearGradient(240, 120, 360, 230)
// 注意从16进制数字创建颜色的方法
gradientT.AddColorStop(0, itk.NewRGBAFromHex("#00FF00FF"))
gradientT.AddColorStop(1, itk.NewRGBAFromHex("0000FFFF"))
gradientT.AddColorStop(0.5, itk.NewRGBAFromHex("FF0000"))
// 渐变色也可以用于线条颜色的渐变
contextT.SetStrokeStyle(gradientT)
// 设置粗一点的线宽以体现渐变色
contextT.SetLineWidth(10)
// 真正绘制三角形
contextT.Stroke()
// 从gg的画布获取Go语言中的image.Image对象
// 注意 := 和 = 作为赋值用,在Gox语言中是等价的
img := contextT.Image()
// 创建一个字节缓冲区,用于存放图片的二进制数据
bufT = new(bytes.Buffer)
// 将生成的图片以PNG格式编码到缓冲区中
image_png.Encode(bufT, img)
// 获取字节缓冲区的字节数组([]byte)类型引用
dataT = bufT.Bytes()
// 设置github.com/sciter-sdk/go-sciter及其子包window的简称
sciter = github_scitersdk_gosciter
window = github_scitersdk_gosciter_window
// 将图片的字节数组数据转换为BASE64编码的字符串
base64StrT := tk.EncodeToBase64(dataT)
// 设置Sciter格式的HTML网页字符串
// 此处非常简单,就是一个网页框架
// 后续DOM操作将由Gox代码来进行
// 注意,为了正确在Sciter中显示中文,最好加上两种meta定义utf-8编码
htmlT := `
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
</head>
<body>
</body>
</html>
`
// 锁定GUI线程,理论上GUI编程都要求在同一线程中更新界面元素
runtime.LockOSThread()
// 创建Sciter窗口,并指定窗口区域位置及大小
w, err := window.New(sciter.DefaultWindowCreateFlag, sciter.NewRect(0, 0, 800, 600))
checkError(err)
// 设置该窗口的一些属性
w.SetOption(sciter.SCITER_SET_SCRIPT_RUNTIME_FEATURES, sciter.ALLOW_FILE_IO | sciter.ALLOW_SOCKET_IO | sciter.ALLOW_EVAL | sciter.ALLOW_SYSINFO)
// 载入HTML页面框架
// 第二个参数是基URL(base url),我们一般不用
w.LoadHtml(htmlT, "")
// 设置窗口标题,注意是中文的
w.SetTitle("图片转向")
// 获取Sciter页面的根元素
rootT, _ := w.GetRootElement()
// 获取body元素
bodyT, _ := rootT.SelectFirst("body")
// 创建一个div,其中文本为空(第二个参数)
divT, _ := sciter.CreateElement("div", "")
// 在body元素中插入div,第二个参数是插入的位置
_ := bodyT.Insert(divT, 0)
// 设置div的innerHTML
// 第二个标志SIH_REPLACE_CONTENT表示替换innerHTML的全部
// 还有可用的标志位有SIH_INSERT_AT_START、SIH_APPEND_AFTER_LAST
// SOH_REPLACE、SOH_INSERT_BEFORE、SOH_INSERT_AFTER,看名字即可知道大意
divT.SetHtml(`<span id="titleTextID">演示图片</span>`, sciter.SIH_REPLACE_CONTENT)
// 设置div的id属性
divT.SetAttr("id", "mainDivID")
// 设置div的style属性(即CSS)
divT.SetStyle("margin-bottom", "10px")
// 获取我们之前定义的span标签
// 这是在设置div的HTML中用文本定义的
// 注意选择器的快捷写法
spanT, _ := bodyT.SelectFirst("span#titleTextID")
// 设置文字颜色为红色
spanT.SetStyle("color", "#ff0000")
// 再创建一个img元素准备装载图片
imgT, _ := sciter.CreateElement("img", "")
// 在body中插入元素,序号为1,也就是第二个元素,即在前面的div之后
_ := bodyT.Insert(imgT, 1)
// 设置该元素的src属性为BASE64格式的图片
imgT.SetAttr("src", `data:image/png;base64,`+base64StrT)
// 设置图片初始的旋转角度为0,即不旋转
imgT.SetStyle("transform", "rotate(0deg)")
// 设置旋转的旋转轴为图片中心点
imgT.SetStyle("transform-origin", "50% 50%")
// 输出目前的根节点的HTML文本以供参考
// 第二个参数为true表示是outerHTML,否则是innerHTML
plv(rootT.Html(true))
// 启动一个goroutine协程,负责图片旋转
// 由于后面的w.Run是阻塞的,所以必须要用线程来处理旋转
// 旋转的方法是不断修改img元素的transform样式的角度值
// 每次顺时针旋转45度
go func() {
angleT := 0
for i= 0; i< 20; i ++ {
// 旋转20次,每次间隔1秒
tk.SleepSeconds(1)
angleT += 45
imgT.SetStyle("transform", fmt.Sprintf("rotate(%ddeg)", angleT))
}
}()
// 显示窗口并运行GUI图形界面
w.Show()
w.Run()
代码中依然有非常详尽的注释,实现思路也非常清晰。附加几点说明:
- 为代码清晰,一些异常情况还是没有处理;
- 输出的结果HTML中,一些属性可能会没有;
- 旋转为20次,通过循环控制,可以设置成无限
- 注意,Gox制作的图形界面程序,如果Windows上不想出现CMD的黑框,可以下载Goxg版本,或者在自行编译时,加上ldflags="-H windowsgui"参数。
注意:
Gox语言是脱胎于Go语言(Golang)的开源脚本语言,解释执行,但相比Go语言更贴近高级语言,语法硬性限制也少一些;是一门偏向快速应用的语言,也可以说是一个集成工具;
-
Gox语言主要优势有三点:
- 第一,Gox语言本身只有一个可执行文件,绿色免配置,下载即可使用,无需安装Go语言环境,无需编译,非常适合快速制作原型以及云服务器上的远程开发;
- 第二,Gox中可以直接使用绝大多数Go语言标准库中的对象和方法函数,也内置了很多常用、优秀的第三方库,充分发挥Go语言多年积累的资源优势;
- 第三,与很多其他主流语言不同,Gox语言着力解决了GUI图形界面编程的问题,内置了基于Giu(imgui)、LCL、Sciter的三套图形界面编程库,直接可以进行快捷高效的图形界面开发(LCL、Sciter只需分别下载一个动态链接库文件,执行和分发时附带上即可),特别适合编写演示原型系统。
作为脚本语言,Gox语言性能肯定不如Go语言这样的编译型语言快,但由于Gox语言与Go语言的紧密联系,Gox语言编写的脚本可以很容易的改写成Go语言代码,编译执行后就可以发挥Go语言的速度优势了。因此,Gox语言也比较适合做初期的Go语言调试,还有一个更直接的方式是使用Gotx(在Gox官网上也有下载),这是使用完全和Go语言一样语法的解释器,可以理解成集成了Go语言标准库和不少第三方库的解释执行的Go语言,一样也不需要搭建Go语言环境。Gotx与Gox的区别在于,Gotx仍然遵循Go语言的文法,代码相对复杂一些,限制也多一些,但改写回Go语言准备编译执行时,基本上没有成本。
Gox的官网在这里,也可以在浏览器搜索引擎中直接搜索“gox语言”,Github页面在这里,在这里可以看到很多Gox语言的学习指南和实际应用实例。
有疑问加站长微信联系(非本文作者)