Go 语言脚本化调用 Excelize 操作 Excel,简洁零依赖,生成独立 EXE

    7

转载自微信公众平台-aardio


Go 有一个开源的 Excelize 很强大,可用于 操作 Excel 表格 。

看着 Excelize 范例里丝滑的 Go 代码,我就想着怎么能弄到 aardio 里用。先尝试把 Go 对象封包到 IDispatch 接口,然后又用 Go 反射整了几个小时,最后都放弃了。

后面继续调整思路,改为调用在运行时用 Go 语法写脚本的 Y aegi (不需要安装 Go 编译环境,体积小速度快,内存加载没有外部依赖 ) ,一顿封装 实现了在 aardio 里运行时执行 Go 代码、读写 Go 变量 、 调用 Go 函数。

一、 aardio 运行 Yaegi(Go 脚本)

aardio 代码示例 :

//创建 Yaegi(Go 脚本)解释器   
import golang.yaegi;  
var go = golang.yaegi();  
  
//直接用 Go 语法写脚本。   
go.eval(`  
package main  
  
//导入内建模块  
import "fmt"   
  
//编写函数  
func Hello(name string)  string {   
    return name;  
}  
   
//全局变量  
var GlobaVal = "这是全局变量";  
`)   
    
//在 aardio 中直接调用 Go 函数   
var ret = go.Hello( "Hello" );   
   
//在 aardio 中修改 Go 全局常量的值  
go.GlobaVal = "新的 Go 全局常量值";  
  
import console.int;  
  
//获取 Go 全局常量的值  
console.log( go.GlobaVal );

二、调用 Excelize 操作 Excel 表格

然后调用 Excelize 就变简单了。

基于上面的原理,我又写了一个 golang.excelize 扩展库。然后 只要直接复制粘 贴 Excelize 官方的 Go 代码范例就可以在 aardio 里用了。

直接看 aardio 代码:

import console.int;   
import golang.excelize;  
var go = golang.excelize();  
  
//直接用 Go 语法写脚本。   
go.eval(`  
package main  
  
import (  
    "fmt"    
      
    //golang.excelize 已经提前导入,不用再下载安装外部模块  
    "github.com/xuri/excelize/v2"  
)  
  
func CreateExcel(path string)  string {  
      
    //下面是 Excelize 官网范例  
    f := excelize.NewFile();  
      
    defer func() {  
        if err := f.Close(); err != nil {  
            fmt.Println(err)  
        }  
    }()  
      
    // 创建新表格.  
    index, err := f.NewSheet("Sheet2")  
    if err != nil {  
        fmt.Println(err)  
        return ""  
    }  
      
    // 设置单元格的值.  
    f.SetCellValue("Sheet2", "A2", "Hello world.")  
    f.SetCellValue("Sheet1", "B2", 100)  
      
    // 设置工作簿的当前激活表格  
    f.SetActiveSheet(index)  
      
    // 保存表格到指定的路径  
    if err := f.SaveAs(path); err != nil {  
        fmt.Println(err)  
    }
    //读单元格的值
    cell, err := f.GetCellValue("Sheet1", "B2")  
    if err != nil {  
        fmt.Println(err)  
        return ""  
    }  
      
    return cell;  
}  
`)   
   
//在 aardio 中直接调用 Go 函数   
var ret = go.CreateExcel( io.fullpath("/hello.xlsx") );  
  
//查看 Go 函数的返回值  
console.log( ret );  

三、 Yaegi 导入第三方模块

这里说一下 Y aegi 导入第三方模块的步骤。

以 aardio 中的 golang.excelize 扩展库为例。打开生成 DLL 的源文件:

"~\lib\golang\excelize\.dll\编译.aardio"

然后在 Go 源码里可以看到这个全局常量:

var Symbols = map[string]map[string]reflect.Value{}  

这个 Symbols 就是符号表,第三方模块都放到这里面。

例如我们要添加 aardio 模块,在创建解释器以后就这么写:

//创建 Yaegi 解释器  
yaegiInterpreter = interp.New(interp.Options{})  
yaegiInterpreter.Use(stdlib.Symbols)   
  
//添加第三方模块  
Symbols["aardio/aardio"] = map[string]reflect.Value{  
        "Call": reflect.ValueOf(aardio.Call),  
        "CallPtr": reflect.ValueOf(aardio.CallPtr),  
        "CallJson": reflect.ValueOf(aardio.CallJson),  
        "JsonParam": reflect.ValueOf(aardio.JsonParam),  
}  
  
//注册到解释器  
yaegiInterpreter.Use(Symbols);

Symbols 可以理解为 aardio 里的表对象,每个键值对注册一个第三方模块。比较坑的地方是这个键名 "aardio/aardio" 要写两次。

如果是非常大的模块,手动写就不现实了。这时候可以用 Yaegi 提供的工具自动生成符号表。为了避免被坑,可以直接运行我提供的 aardio 代码生成,以 Excelize 为例:

//提取符号表  
import console.int;   
import golang;  
   
var go = golang("/","1.22.3")   
go.mod("init excelize")   
go.get("github.com/xuri/excelize/v2")   
go.yaegiExtract("github.com/xuri/excelize/v2")

没有任何显示是正常的,耐心等到完成。打开自动生成的

  • github_com-xuri-excelize-v2.go

有了前面的知识,看生成的代码你就知道怎么做了。

四、Yaegi(Go 脚本)回调 aardio 函数

直接看代码:

//aardio 回调函数  
import golang.yaegi;  
var go = golang.yaegi();  

go.eval(`  
package main  
   
import "aardio"     

func TestCallBack(fnCallback float64) int{  
      
    var s = "字符串"  
       
    var r,_ = aardio.CallJson( fnCallback ,s,123,map[string]int{"id": 1, "id2": 2} )  
       
    return r  
}  

`)   

import raw.jsonCall  
    
//创建回调函数指针, 在 Go 中必须用 aardio.CallJson 调用。  
var callback = raw.jsonCall(  
    function(a,b,c){   
        console.log("回调参数:",a,b)   
        console.dumpJson(c);  
        return 123;  
    } );  

import console.int   

var ret  = go.TestCallBack( callback )  

console.log(ret);

回调可以支持任意个数 JSON 兼容的参数,传参与返回值会自动通过 JSON 转换。

要注意在 aardio 中调用 Yaegi 函数时,数值默认是 float64 类型( JSON 只能描述一种数值类型 ),可以在 Go 函数里强制转换一下就可以了。

五、Yaegi(Go 脚本)调用 aardio 窗口函数

直接看代码:

import golang.yaegi;  
var go = golang.yaegi();  

go.eval(`  
package main   
import "aardio"     

func TestCallBack(hwnd float64){   
    aardio.Call(hwnd,"onCallback","参数1","参数2");  
}  
`)   

import win.ui;  
var winform = win.form(text="Yaegi")  
winform.add(  
edit={cls="edit";left=43;top=27;right=717;bottom=400;multiline=1;z=1}  
)  

winform.onCallback = function(param1,param2){  
    winform.edit.print("Go 调用了 aardio 函数,参数:",param1,param2)  
}  

go.TestCallBack( winform.hwnd );  
   
winform.show();  
win.loopMessage();
消息盒子

# 暂无消息 #

只显示最新10条未读和已读信息