Gox语言和Gotx中用Sciter做GUI图形界面时如何进行调试-GX40

本文以实例来讲解了在Gox语言和Gotx中使用Sciter来进行GUI图形界面编程时如何进行调试。

  • 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语言的学习指南和实际应用实例。

Gox语言和Gotx都支持使用Sciter来进行GUI图形界面编程,Sciter是经过商用实践检验的跨平台界面开发包。

  • Sciter包主要利用HTML/CSS/TiScript来进行图形界面开发,可以开发本地GUI界面;Gox中通过Go语言的绑定包来与Sciter互动,可以互相传递数据或者调用函数;也可以通过Gox代码控制界面中的DOM元素,甚至执行回调函数;

  • Gox语言和Gotx中使用Sciter包,只需要在执行或分发时附带一个动态链接库文件,Windows下已经随Gox的压缩包一起提供了,也可以用gox -initgui或gotx -initgui命令自动获取最新的DLL文件;Linux或MacOS下请参看这里的安装说明,只需进行前两步安装动态链接库的步骤即可;

  • 尽管Sciter内置的HTML+CSS+TiScript方式与内嵌通用WebView控件的方式有所不同,主要是不支持JavaScript,但Sciter已被证明是非常优秀的跨平台GUI图形界面编程库,经过很多公司和商用产品的实际检验,稳定可靠。我们常见的包括TeamViewer,Symantec,Vmware,Evernote,360等公司或产品都使用了Sciter来制作界面,可见Sciter相当值得信赖。

下面我们来看看在用Sciter制作GUI图形界面时,如何进行有关的调试。

Sciter包下载解压缩后,目录结构大概是这样的,

Sciter包解压缩后目录结构

以Windows平台为例,目前基本都已经是64位的,因此进入bin.win文件夹中,找到x64目录(如果是amd CPU的需要选择amd64),

x64目录

将其中的sciter.dll复制出来,拷贝到Gox或者Gotx主程序所在的相同目录,也可以复制到系统路径中的目录下,例如c:\windows\system32目录下,这样即可支持在Gox或Gotx中进行Sciter图形界面编程了。

我们来做一个最简单的例子,下面是一个用Gox语言编写Sciter界面的代码:

// 设置两个Sciter包的简称
sciter = github_scitersdk_gosciter
window = github_scitersdk_gosciter_window

// htmlT中将是在Sciter界面中载入的HTML页面文本
// 其中self.ready()函数类似JQuery中的$(document).ready函数
// 在其中定义了按钮2点击后的回调函数,调用了Gox语言中定义的prints函数
htmlT = `
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title>Sciter演示</title>
    <script type="text/tiscript">
        function self.ready() {
            $(#btn2).onClick = function() {
                view.prints("按钮2被点击了");

                this.html = "已点击";
            };
        }
    </script>
</head>
<body>
    <button id="btn1">按钮1</button>
    <button id="btn2">按钮2</button>
    <button id="btn3">按钮3</button>
</body>
</html>
`

// 锁死GUI线程,理论上所有图形界面操作应该在一个线程中进行
runtime.LockOSThread()

// 创建Sciter对象,并设置大小位置为默认
w, err := window.New(sciter.DefaultWindowCreateFlag, sciter.DefaultRect)
if err != nil {
    log.Fatal(err)
}

// 载入HTML文本
w.LoadHtml(htmlT, "")

// 设置图形窗口标题
w.SetTitle("Sciter演示")

// 设定一个Gox语言函数供TiScript中调用
// 注意输入输出参数的转换方式
w.DefineFunction("prints", func(args) {
    fmt.Println(args[0].String())

    return sciter.NewValue("")
})

// 选择界面中的根元素
root, _ := w.GetRootElement()

// 选取id为btn1的元素,即按钮1
btn1, _ := root.SelectById("btn1")

// 设置按钮1点击后的Gox语言回调函数
btn1.OnClick(func() {
    fmt.Println("btn1被点击了")

    btn1.SetStyle("color", "#FF0000")

    fmt.Println(btn1.Html(true))
    btn1.SetHtml("已点击", sciter.SIH_REPLACE_CONTENT)

})

// 显示Sciter图形界面并开始运行之
w.Show()
w.Run()

代码中注释很详细,执行后效果如下:

Gox+Sciter界面效果

点击按钮1和按钮2后,都会有相应的反应。

上面的例子用Gotx来编写同样的功能代码(实际上就是Go语言代码)如下:

package main

import (
    "fmt"
    "log"
    "runtime"

    "github.com/sciter-sdk/go-sciter"
    "github.com/sciter-sdk/go-sciter/window"
)

func main() {
    // htmlT中将是在Sciter界面中载入的HTML页面文本
    // 其中self.ready()函数类似JQuery中的$(document).ready函数
    // 在其中定义了按钮2点击后的回调函数,调用了Gotx语言中定义的prints函数
    htmlT := `
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title>Sciter演示</title>
    <script type="text/tiscript">
        function self.ready() {
            $(#btn2).onClick = function() {
                view.prints("按钮2被点击了");

                this.html = "已点击";
            };
        }
    </script>
</head>
<body>
    <button id="btn1">按钮1</button>
    <button id="btn2">按钮2</button>
    <button id="btn3">按钮3</button>
</body>
</html>
`

    // 锁死GUI线程,理论上所有图形界面操作应该在一个线程中进行
    runtime.LockOSThread()

    // 创建Sciter对象,并设置大小位置为默认
    w, err := window.New(sciter.DefaultWindowCreateFlag, sciter.DefaultRect)
    if err != nil {
        log.Fatal(err)
    }

    // 载入HTML文本
    w.LoadHtml(htmlT, "")

    // 设置图形窗口标题
    w.SetTitle("Sciter演示")

    // 设定一个Go语言函数供TiScript中调用
    // 注意输入输出参数的转换方式
    w.DefineFunction("prints", func(args ...*sciter.Value) *sciter.Value {
        fmt.Println(args[0].String())

        return sciter.NewValue("")
    })

    // 选择界面中的根元素
    root, _ := w.GetRootElement()

    // 选取id为btn1的元素,即按钮1
    btn1, _ := root.SelectById("btn1")

    // 设置按钮1点击后的Go语言回调函数
    btn1.OnClick(func() {
        fmt.Println("btn1被点击了")

        btn1.SetStyle("color", "#FF0000")

        fmt.Println(btn1.Html(true))
        btn1.SetHtml("已点击", sciter.SIH_REPLACE_CONTENT)

    })

    // 显示Sciter图形界面并开始运行之
    w.Show()
    w.Run()

}

用Gotx来执行这段代码后的效果也是完全一样的:

Gotx+Sciter界面效果

下面来说如何调试,由于Gox语言和Gotx是基本类似的(从前面代码也可以看出来,除了开头的包声明和引用声明,两者区别主要在prints函数的定义上,Gox语言中无需指定参数类型,也无需指定返回值),因此下面将仅以Gotx代码即Go语言(Golang)为例来演示。

首先,如果准备将调试信息都输出到命令行界面上,可以直接用上面例子中定义的prints方法。在Gox语言或Gotx中定义的函数,传递给Sciter后,均可以直接作为全局对象view的成员函数调用。由于这样定义的函数,参数需要做类型转换,因此实现printf这样的可变个数参数存在问题,所以最好TiScript中实现可变参数处理,TiScript也是功能齐全的脚本语言,处理这些自然不成问题。这样的话,prints函数不用变,在TiScript则将输出信息时的语句改成类似下面的即可:

view.prints(String.printf("按钮2被点击了: %s", new Date()));

这里使用了TiScript中的String对象的printf函数,功能类似于其他语言中的sprintf函数,支持可变参数,Date对象则是获取当前系统时间用的,执行效果如下:

可变参数的处理

然后,Sciter也支持类似一般浏览器中的开发者调试模式,这需要使用Sciter提供的调试工具Inspector,这个工具也是随着Sciter SDK包下载时附带在其中的。

还是以64位Windows为例,在Sciter SDK包解压缩后的bin.win/x32子目录下可以找到inspector.exe这个就是Sciter提供的调试工具Inspector了。

Inspector程序位置

注意,即使是64位Windows,也需要到32位的目录下找到这个工具。运行它之后,看到下面的界面,就可以开始调试Sciter代码了。

Inspector初始界面

在Inpector启动的界面上,已经有了如何使用的简单说明,最主要有两个方式让Sciter程序连接Inspector,第一是直接在运行图形界面程序时按Ctrl-Shift+I组合键即可,第二则是在TiScript中加上如下的代码:

        if (view.connectToInspector) {
            view.connectToInspector(rootElement, inspectorIpAddress);
        }

例如,我们刚才的例子程序运行时,按Ctrl+Shift+I组合键就可以看到Inspector中展现了如下的界面。

Sciter的调试界面

熟悉Web开发的人马上就会知道这就是很熟悉的开发者调试界面了,可以查看Sciter界面的HTML的DOM树与CSS等,也有控制台。与一般的Web调试界面和Javascript不同的是,Sciter中向控制台输出的脚本命令有所不同。

我们来修改按钮2的点击回调函数为:

            $(#btn2).onClick = function() {
                view.prints(String.printf("按钮2被点击了: %s", new Date()));

                stdout.println("1 + 2 = ", 1+2);

                var result = 1.61 / 2.23;

                debug info ( result = {result});
                debug alert ( this is a warning {2*5});

                this.html = "已点击";
            };

再次执行Gotx例子代码并点击按钮2之后看到Inspector中控制台的输出如下:

使用Sciter的控制台输出命令

Sciter调试中,在TiScript中支持stdout、stderr和stdin,而它们和一般语言一样支持printf、pringln等函数,可以在控制台输出信息。

另外,Sciter不支持Javascript中的console.log()函数,但支持功能更强的debug关键字,格式是:

debug [log | info | warning | alert] : <space-separated-list-of-expressions> ;

或者

debug [log | info | warning | alert] ( <stringizer-function-parameters> )

第二种写法使用到了Sciter支持的特殊的stringizer写法,在后面括号中,无需像其他语言中一样给字符串加上双引号,直接写就行了,花括号中才是需要替换的变量或者表达式。请仔细参看例子中的写法。

debug也支持log、info、warning、alert四种类型的信息,分别用不同的图标来表示。