由于Gox 1.56a版本之后已经不支持Giu库,因此本文档仅用作留存参考
Gox中使用Giu库进行GUI图形界面编程比较方便,唯一需要注意的是该库依赖于GLFW和OpenGL,有些虚拟机可能不支持,此时,Gox语言也支持LCL库(请参见本系列有关文章),如何选择可以按自己所需考虑。
Gox中使用该库引用gui包即可,也是无需全路径名。
我们直接来看例子,实现一个简单计算器的代码如下:
// text1 used to hold the string value of the text input
// notice: text1 is a pointer
text1 = new(string)
onButton1Click = fn() {
// evaluate the expression in the text input
rs = eval(*text1)
// set the result back into the text input
setValue(text1, rs)//string(rs)
}
// close the window, also terminate the application
onButton2Click = fn() {
exit()
}
// main window loop
loop = fn() {
// set the layout of GUI
layoutT = []gui.Widget{
gui.Label("Enter an expression."),
gui.InputText("", 0, text1),
// widgets in line layout is aligned left to right
gui.Line(gui.Button("Calculate", onButton1Click),
gui.Button("Close", onButton2Click)),
}
gui.SingleWindow("Calculator", layoutT)
}
// setup the title, size (width and height, 400*200), style and font-loading function of main window,
mainWindow = gui.NewMasterWindow("Calculator", 400, 200, gui.MasterWindowFlagsNotResizable, nil)
// show the window and start the message loop
gui.LoopWindow(mainWindow, loop)
执行的效果如下:
界面布局的代码很好理解,具体界面控件的文档和例子请参考Giu的Github页面。另外需要注意,text1是一个字符串指针,所以取值要用“*”,而设置值需要用setValue内置函数。
下面是一个简单的代码编辑器的例子,支持中文,支持文件的打开、保存和另存,支持命令行打开代码,支持代码加密解密和运行,唯一不足大概就是还不支持语法高亮和代码自动完成了:
argsG = os.Args
lenT = len(argsG)
editFileNameG = ""
editFileCleanFlagG = ""
editSecureCodeG = new(string)
fcT = ""
if lenT < 3 {
editFileNameG = ""
editFileCleanFlagG = "*"
} else {
editFileNameG = argsG[2]
fcT = tk.LoadStringFromFile(editFileNameG)
if tk.IsErrorString(fcT) {
gui.SimpleError("错误提示", "载入文件时发生错误:%v", tk.GetErrorString(fcT))
return
}
editFileCleanFlagG = ""
}
// hold the text in main edit control
text1 = new(string)
setValue(text1, fcT)
onEditChange = func() {
editFileCleanFlagG = "*"
}
onButtonLoad = func() {
if editFileCleanFlagG != "" {
rs = gui.GetConfirm("请确认", "文件已被修改,确认要打开另一个文件吗?")
if rs == false {
return
}
}
fileNameNewT = gui.SelectFile("请选择要打开的文件", "所有文件", "*")
if tk.IsErrorString(fileNameNewT) {
if tk.EndsWith(fileNameNewT, "Cancelled") {
gui.MessageBox("信息", tk.Spr("操作被用户取消"))
return
}
gui.MessageBox("错误提示", tk.Spr("选择文件失败:%v", tk.GetErrorString(fileNameNewT)))
return
}
fcT = tk.LoadStringFromFile(fileNameNewT)
if tk.IsErrorString(fcT) {
gui.MessageBox("错误提示", tk.Spr("载入文件内容失败:%v", tk.GetErrorString(fileNameNewT)))
return
}
editFileNameG = fileNameNewT
setValue(text1, fcT)
editFileCleanFlagG = ""
}
onButtonRunClick = func() {
rs = runScript(*text1, "")
gui.MessageBox("运行结果", tk.Spr("%v", rs))
}
editorSaveAs = func() {
fileNameNewT = gui.SelectSaveFile("请选择要保存的文件", "所有文件", "*")
if tk.IsErrorString(fileNameNewT) {
if tk.EndsWith(fileNameNewT, "Cancelled") {
gui.MessageBox("信息", tk.Spr("操作被用户取消"))
return
}
gui.MessageBox("错误提示", tk.Spr("选择文件失败:%v", tk.GetErrorString(fileNameNewT)))
return
}
editFileNameG = fileNameNewT
rs1 = tk.SaveStringToFile(*text1, editFileNameG)
if rs1 != "" {
gui.MessageBox("错误提示", tk.Spr("保存文件失败:%v", rs))
return
}
gui.MessageBox("信息", tk.Spr("文件已被保存至:%v", editFileNameG))
editFileCleanFlagG = ""
}
editorSave = func() {
if editFileNameG == "" {
editorSaveAs()
return
}
rs = false
if tk.IfFileExists(editFileNameG) {
rs = gui.GetConfirm("请确认", "文件已存在,是否要覆盖?")
}
if rs == true {
rs1 = tk.SaveStringToFile(*text1, editFileNameG)
if rs1 != "" {
gui.MessageBox("错误提示", tk.Spr("保存文件失败:%v", rs))
return
}
gui.MessageBox("信息", tk.Spr("文件已被保存至:%v", editFileNameG))
editFileCleanFlagG = ""
}
}
editEncrypt = func() {
gui.CloseCurrentPopup()
sourceT = *text1
encStrT = tk.EncryptStringByTXDEF(sourceT, *editSecureCodeG)
if tk.IsErrorString(encStrT) {
gui.SimpleError("错误提示", tk.Spr("加密失败:%v", tk.GetErrorString(encStrT)))
return
}
setValue(text1, "//TXDEF#" + encStrT)
editFileCleanFlagG = "*"
setValue(editSecureCodeG, "")
}
editEncryptClick = func() {
gui.OpenPopup("请输入密码##EncryptInputSecureCode")
}
editDecrypt = func() {
gui.CloseCurrentPopup()
sourceT = tk.Trim(*text1)
encStrT = tk.DecryptStringByTXDEF(sourceT, *editSecureCodeG)
if tk.IsErrorString(encStrT) {
gui.SimpleError("错误提示", tk.Spr("解密失败:%v", tk.GetErrorString(encStrT)))
return
}
setValue(text1, encStrT)
editFileCleanFlagG = "*"
setValue(editSecureCodeG, "")
}
editDecryptClick = func() {
gui.OpenPopup("请输入密码##DecryptInputSecureCode")
}
onButtonCloseClick = func() {
exit()
}
loop = func() {
layoutT = make(gui.Layout)
layoutT = append(layoutT, gui.Label(editFileNameG + editFileCleanFlagG))
layoutT = append(layoutT, gui.InputTextMultiline("InputTextMultiline001", text1, -1, -30, 0, nil, onEditChange))
layoutT = append(layoutT, gui.Line(gui.Button("打开", onButtonLoad), gui.Button("保存", editorSave), gui.Button("另存为", editorSaveAs), gui.Button("加密", editEncryptClick), gui.Button("解密", editDecryptClick), gui.Button("运行", onButtonRunClick), gui.Button("关闭", onButtonCloseClick)))
layoutT = append(layoutT, gui.PopupModal("请输入密码##EncryptInputSecureCode", []gui.Widget{gui.Line(gui.Label("密码"), gui.InputTextV("", 40, editSecureCodeG, gui.InputTextFlagsPassword, nil, nil)),
gui.Line(gui.Button("确定", editEncrypt), gui.Button("取消", func() { gui.CloseCurrentPopup() })),
}))
layoutT = append(layoutT, gui.PopupModal("请输入密码##DecryptInputSecureCode", []gui.Widget{
gui.Line(gui.Label("密码"),
gui.InputTextV("", 40, editSecureCodeG, gui.InputTextFlagsPassword, nil, nil)),
gui.Line(gui.Button("确定", editDecrypt),
gui.Button("取消", func() { gui.CloseCurrentPopup() })),
}))
// add this to the layout if you would use gui.MessageBox function later
layoutT = append(layoutT, gui.PrepareMessageBox())
gui.SingleWindow("Gox编辑器", layoutT)
}
osNameT = tk.GetOSName()
if tk.Contains(osNameT, "darwin") {
setVar("Font", "/Library/Fonts/Microsoft/SimHei.ttf")
} else {
setVar("Font", "c:/Windows/Fonts/simsun.ttc")
}
setVar("FontRange", "COMMON")
setVar("FontSize", "15")
mainWindow = gui.NewMasterWindow("Gox编辑器", 800, 600, 0, gui.LoadFont)
gui.LoopWindow(mainWindow, loop)
运行效果如下:
注意,代码中的text1用于存放代码,editSecureCodeG用于存放密码框密码,都需要使用字符串指针,留意它们的写法。
最后,注意图形界面编程的统一禁忌是:只能在一个线程中操作图形界面。