• Aardio 第一天:使用虚表和适配器


    初识 Aardio

    挺洋气的名字,乍看神似arduino的重新排序。不过这是一种国人开发的脚本编程语言,自带基于win32 api的界面框架,可以和其他编程语言沟通,比如调用java或者python代码。

    官网下载下来6.5MB的压缩包,解压后,打开集成开发环境,它还会远程下载组件,比如粘贴了vlist的示例代码后,点击硕大的运行按钮,会要求安装vlist组件,确认即可。

    也可以从网上下载 .aardio 文件,自己放到lib文件夹中,作为开源库使用。这对于开源很友好,也可以魔改、借此入门,aardio上层都是开源的。

    aardio 项目编译之迅速,可以让你暂时忍受其编辑器界面与错误提示界面之简单……

    aardio 制作的小工具很赞,可谓精悍,比如Gif123录屏软件,如果你有制作gif动图教程的打算,不妨试试。Gif123可以在多显示器环境下工作,跨越扩展显示屏进行录屏。用SPY++探测了一下,发现界面不是directui,拖动条等控件都有自己的窗口句柄。那么,aardio 显示无限列表的性能如何呢?


    使用虚表和适配器

    aardio 的 vlist 有 createTableAdapter 方法,里面封装了 getCount,getItem等类似于安卓listview适配器的接口,令人欣慰。但是网上的vlist demo无法正常运行:
    请添加图片描述
    而且这个命令行窗口也无法复制错误信息,令人烦躁。

    好在aardio还有其他更好的虚表示例程序,如: aardio - 【库】虚表增强版。增强了vlist,是一个新的控件了,需要从他博客下载 vlistEx.rar、_.rar,解压出 .aardio 文件放入lib/godking文件夹中。这样就可以运行他博客中的代码了。

    但是示例程序中的虚表,与我想象中的不同,仍像是普通的列表,需要提前加装一行行的数据。其实参考库文件中的setTable方法,可以自己写适配器的!代码如下:

    import win.ui;
    
    import godking.vlistEx;
    
    import godking
    /*DSG{{*/
    mainForm = win.form(text="vlistEx - table adapter";right=849;bottom=578)
    mainForm.add(
    vlist={cls="vlistEx";left=10;top=10;right=840;bottom=570;db=1;dl=1;dr=1;dt=1;edge=1;transparent=1;z=1}
    )
    /*}}*/
    
    var t = { fields={"序号","姓名","年龄","地址","身份证"} }
     
    math.randomize()
    for(i=1;100;1){
        var tt={}
    	tt["序号"]="[@rowindex]"  // 行序号标记是不允许编辑修改的
    	tt["姓名"]=math.random(1000,9999)+"姓名"
    	tt["年龄"]=math.random(10,99)
    	tt["地址"]=math.random(1000,9999)+"地址"
    	tt["身份证"]=math.random(1000,9999)+"身份证"
    	..table.push(t,tt)
    }
    
    // 直接把 setTable  方法复制到demo中。将this.改成lv.
    	setTable = function(lv, dataSource,fields,colwidth,colstyle,toArray=false,toUtf8=false){
    		lv.setRedraw(false);
    		..table.clear(lv.dataAdapter._dataSource);
    		dataSource = ..table.clone(dataSource);
    		// 初始化标题栏
    		if(!fields){ //如果没有指定标题栏,则自动生成标题栏。
    			if (dataSource[["fields"]]) fields=dataSource[["fields"]] //如果指定了fields字段
    			else fields = ..table.keys(dataSource[[1]]);// 如果没指定fields字段,且数据为字典型,则字典关键字为字段。
    		} 
    		if (type(fields)="string") fields=..string.split(fields,",;");//将字符串转换为“表”
    		if (type(fields)!="table" or !#fields) fields=null; //取消非法字段指定
    		// 填充数据
    		if (#fields){ //如果是字典,有了字段
    			// 先按字段刷新标题栏。
    			var curfields = lv.getColumnText();
    			if (#fields!=#curfields or ..table.tostring(curfields)!=..table.tostring(fields)) {
    				lv.setColumns(fields,colwidth,colstyle);
    			}
    			// 判断是否为字典
    			if #..table.keys(dataSource[1]){
    				if !dataSource["fields"] dataSource.fields=fields;
    				// 字典转数组
    				if toArray dataSource=lv.dictToArray(dataSource);
    			} else {
    				// 如果既不是字典,也不是空,则确定为数组。则取消fields字段。否则保持原dataSource的fields设置。
    				if #dataSource[1] dataSource.fields = null;
    			}
        	}else{ //如果是数组,则按照数组1的成员数,生成列数。
        		if type(dataSource[[1]])!=type.table {
        			lv.setColumns();
        			return lv.setRedraw(true); 
        		}
    			if (lv.columnCount!=#(dataSource[[1]])){
    				lv.setColumns(..string.split(..string.repeat(#(dataSource[[1]]),' ')),colwidth,colstyle);
    			}
    		}
    		if toUtf8 {
    			if dataSource.fields {
    				for(i=1;#dataSource;1){
    					for(k,v in dataSource[i]){
    						if type(v)=type.string dataSource[i][k] = ..string.fromto(v,0,65001);
    					}
    				}
    			} else {
    				for(i=1;#dataSource;1){
    					for(n=1;#dataSource[i];1){
    						if type(dataSource[i][n])=type.string dataSource[i][n] = ..string.fromto(dataSource[i][n],0,65001);
    					}
    				}
    			}
    		}
    		tableAdapter(lv/*listview*/,dataSource).update();
    		lv.setRedraw(true);
    	}
    	
    //自己写适配器!爽歪歪
    class tableAdapter {
    	ctor (listview,dataSource) {
    		this._listview = listview;
    		this._dataSource = dataSource;
    		if( listview.dataAdapter ) listview.dataAdapter.__close();
    		listview.dataAdapter = this; 
    		this.update = function(){
    			::SendMessageInt(listview.hwnd, 0x102F/*_LVM_SETITEMCOUNT*/,this.count(), 0x2/*_LVSICF_NOSCROLL*/);
    		}
    		this.__close = function(){ this._listview.dataAdapter = null; };
    		this._columns = dataSource.fields;
    	};
    	count = function () {
    		return 100000000; // 一个小目标的数据量,惊不惊喜,
    	};
    	getItem = function (row, col) {
    		return row +','+ col; // 意不意外?
    	}
    }
    
     
    //mainForm.vlist.setTable(t,,{80,100,100,0,200},0x2/*_LVCFMT_CENTER*/)
    //tableAdapter(mainForm.vlist/*listview*/).update();
    //tableAdapter(mainForm.vlist/*listview*/, t).update();
    setTable(mainForm.vlist, t,,{80,100,100,0,200},0x2/*_LVCFMT_CENTER*/)
    
    mainForm.vlist.setCheckBox(true)
    mainForm.vlist.textColor = 0xFF0000;
    mainForm.vlist.bkColor = 0xEEEEEE;
    mainForm.vlist.setHeaderHeight(50);
    mainForm.vlist.lineColorH = 0x008800;
    mainForm.vlist.lineColorV = 0xBB9999;
    mainForm.vlist.fillParent(4)
     
    mainForm.vlist.onEditBegin = true; 
     
    mainForm.vlist.onEditEnd = function(row/*行*/,col/*列*/,text/*内容*/){
    	/*单元格编辑完毕,是否允许单元格内容改变。返回false不允许,返回true允许,返回文本则改为新文本*/
    	/*不定义此事件,则默认允许改变。注意:只有onEditBegin事件返回true,此事件才会触发。*/
     
    	// 确保第三列输入数值!
    	if col==3 {
    		var r = ..tostring((..tonumber(text)):0);
    		if r!=text	{
    			..win.msgbox(f(`"{text}" 将转为:"{r}"`));
    			return r; 
    		}
    	}
    	return true; 
    }
     
    mainForm.vlist.onSortColumn = function(col,desc){
    	/*点击列标题进行排序。col:列号,从1开始。desc:是否倒序。返回true重置标题栏排序图标*/
    	..table.sortEx(owner.getTable(),col,desc,/*数据转换*/)
    	owner.update()
    	return true;
    }
     
    mainForm.vlist.onRClick = function(row/*行*/,col/*列*/){
    	/*鼠标右键点击项目事件*/
    	..win.msgbox(f("您鼠标右键点击了:{row}行,{col}列"))
    }
     
    mainForm.show();
    win.loopMessage();
    

    可以看到适配器接口class tableAdapter很简单,但是setTable那一坨东西是在干啥,暂时还没搞明白……

    直接运行会出错,因为vListEx.aardio第201行访问了原_dataSource列表数据,注释掉即可。

    //if this.dataAdapter._dataSource[item.iItem].checked { …
    

    运行效果:

    请添加图片描述

    aardio 的虚表似乎还是基于win32原生的列表控件,但是能够实现虚表,令人眼前一亮。aardio 语法像js或者java,比autohotkey脚本的语法好写易懂。

    虽然有着悠久的历史,但是对我而言,这是一门新技术、新思路。祝愿这门自带界面框架的脚本语言,引擎越来越快、开源的生态越来越好!

    调用 Java 包,由Java层提供列表数据

    1. IDEA新建纯Java项目,写一些类和方法。然后管理项目结构(文件夹+三个小方块的那个图标),在Artifact区域新建Artifact,选择导出编译结果为jar,最后build Artifact,可以在磁盘上找到jar。将生成的mdict-java-core.jar复制到项目的Java文件夹中

    2. 本例测试的是词典库Mdict-Java。脚本代码如下:

    import java; 
    var jvm = java(); 
    Mdict = jvm.import("com.knziha.plod.dictionary.mdict");
    var md = Mdict("D:/assets/mdicts/OED2.mdx");
    
    …… 修改适配器代码 ……
    
    getItem = function (row, col) {
    	return md.getEntryAt(row); // 获取词条名称
    }
    

    效果图:
    请添加图片描述
    不知道怎么样才能正确导入绝对路径中的class文件,试了好久没成功,最后直接把jar复制到项目java文件夹了,不去管。

    列表项目数量超过一亿显示空白,不知是哪里的问题。

    感觉性能还可以,快速拖拽滚动条的时候有轻微卡顿,可忽略。资源占用有所增加,但也不是很大。导出exe失败:不能发布,说生成失败,添加资源失败,然而没有资源,纯代码项目而已。

  • 相关阅读:
    公众号开发教程:微信视频预览一半就要收费是怎么做的
    启发式搜索 :A*算法详解
    JAVA如何保留小数点后两位
    聊聊探索式测试理论与实践(合辑共9篇)
    CH11_重构API
    SSM学习42:SpringMVC入门案例(重点)
    机器学习-期末复习
    前端面试的话术集锦第 18 篇博文——高频考点(HTTP协议 & TLS协议)
    给Python 脚本用optparse传参及用法
    QT基础教学(QT对象间的关系)
  • 原文地址:https://blog.csdn.net/sinat_27171121/article/details/127089355