aardio,你用过吗?

发布时间 2023-05-31 17:31:37作者: 钟小嘿

话不多说,选择重点说明。

1.引入java类

当需要使用java类时,只需将其放入java文件夹下即可,具体包名可以自定义。实际上为了方便,会先创建包,然后创建java类,在里面编写代码后,将其编译为class文件,即可引入使用。(还有一种方式就是只编写java代码,然后通过aardio自带的命令进行编译,但本人主要写java的,所以直接编译成class)

重点有以下几个:

①aardio在引入时只需要.class文件,其实并不需要.java文件,放java文件是为了方便编辑源码;

可以在java文件所在目录打开cmd通过javac命令进行编译

javac -encoding UTF-8 MD5Utils.java

②包名一定要对应(class文件和引入时的包名);

 ③若java文件中引入了外部的jar,则需要将其放入java文件所在目录,然后再编译,同时需要指定jar(当有多个jar时,之间使用;分隔)

javac -encoding UTF-8 -cp commons-codec-1.15.jar MD5Utils.java

编译为class文件后即可使用,然后调用其方法,其中上述截图的引入的java代码部分截图如下

 2.自定义用户库

当一些重复的代码,按照java的思想是一定要进行封装的,比如工具类。下面对MD5的工具类进行封装说明(需要引入java)

只需要在用户库新建库,然后在里面编写方法即可。需要注意的是,这里要使用外部的包,必须要使用..

定义后在调用的代码中先导入,然后使用即可

3.判断程序是否重复运行

一般情况下,一个应用程序启动后,只会创建一个实例,不会重复的启动,那么就可以通过窗口局句柄来进行判断

第一步,先获取唯一的实例ID

先在右侧的工具里面生成了GUID,这个ID几乎是国际唯一的,可以用来唯一标识应用。

第二步,引入所需要的包,获取窗口并进行判断

 当启动后,再次运行就会提示,只能退出后再运行。

4.常见的命令和方法

4.1命令

常规的一些命令如下表,方法的参数在此略,具体的在调用时会有提示

方法名 说明 引入 示例
process.execute() 执行某个进程 import process

process.execute("/QQ.exe");启动QQ的应用程序

process.kill() 强制杀死某个进程 import process

process.kill("/QQ.exe");强制关闭QQ程序

loadcodex() 动态加载并运行aardio代码 -

见后续示例

loadcode() 加载aardio代码 -

见后续示例

win.getText() 获取窗口句柄的文字(窗口标题) -

winform.msgbox(win.getText(winform.hwnd))

table.push() 向数组尾部添加一个或多个元素,返回数组大小 -

var arr={};table.push(arr,1);

table.insert() 向数组头部添加一个或多个元素,返回数组大小   var arr={};table.push(arr,1);
table.clear() 清除数组中的所有元素 - var arr={1,2,3};table.clear(arr);

 

1)loadcodex()示例

使用loadcodex可减少主文件中的代码量,对不同的逻辑进行分离,通过动态加载,可以减少界面的卡顿。

先定义一个代码文件tools.aardio,用于进行业务的处理,这里以获取笑话为例(通常工具类是放在用户库(lib文件夹下),业务的处理单独处理)

import web.rest.jsonClient;

var http = web.rest.jsonClient();
var url="https://autumnfish.cn/api";

//获取笑话
getJokes = function(){
   return  http.get(url+"/joke/list?num=10")
}

使用loadcodex加载tools.aardio,并调用其中的方法

winform.button.oncommand = function(id,event){
    //加载文件
    loadcodex("\function\tools.aardio");
    //可直接调用方法,因为此时文件已加载
    var context = getJokes()
    winform.msgbox(context)    
}

需要注意的是,这里引入后可直接使用方法。那么在多个文件定义方法时尽量避免重名,否则在调用时,则会以最后的那个方法为准。
2)loadcode()示例

loadcode()和loadcode()x是很类似的。其原型是

函数对象,错误信息 = loadcode( codeString | filepath )

loadcode()仅仅加载代码,该函数并不立即执行代码,而是返回一个函数对象,然后在需要使用的时候才会运行其代码。如果加载代码失败,则返回的函数对象为null值,并在第二个返回值中返回错误信息.

loadcodex()加载代码并且运行代码,重在立即执行里面的代码。

如果只是想运行一下代码用loadcodex()就可以,如果是想加载了代码以后反复运行,就先用 loadcode() 加载为一个函数对象,然后再去调用。

先定义一个文件tools2.aardio

在主文件main.aardio加载

 在我看来,其实loadcodex()完全可以替代loadcode()。至于两者在性能上有何不同,暂不可知。

4.2 按行读取txt文件

readline = function(path){
    var txt = string.load(path);
    if(txt==null){
        return null;
    }
    return string.split(txt,'<\r\n>');
}

可以使用string类来读取文件,然后通过换行符进行分隔,返回按行组成的数组。

5.全局变量的定义与使用

有时可以需要在main.aardio中定义全局变量,然后在其他的文件中使用,因此全局变量也是很重要的,也非常的简单,只需要使用..修饰,就是全局变量

如在main.aardio定义数据类型

然后在文件中使用即可

6.提示框

6.1 msgbox-默认对话框

其语法如下(标题可省略,默认为当前窗口的标题【属性-标准-标题】)

 对于普通的消息提示,可以直接使用,不过需要点击确定。

对于错误的提示,也可以提示

6.2 msgOk、msgErr、msgInfo、msgAsk-提示框

msgOk其语法如下,其他类似,使用时需要导入包win.dlg.message

 对于成功的操作可进行正确的提示,然后使其自动关闭。

同理,操作失败也可以进行提示

那么,对于普通的消息提示,不区分正确和错误,也是可以进行提示

除此之外,其也提供了询问的对话框,样式还是比较好看的。

语法如下:

 示例截图如下:

 

对于普通的消息提示,除了图标是感叹号外,还可以显示皱眉、大拇指、倒竖大拇指,警告

                         

                             

  

6.3  msgboxTest-询问对话框  

 其语法如下(标题可省略)

 对于需要询问的对话框,采用这种方式最佳。

这里点击确定或取消,进行了消息的提示,实际场景可根据需要进行逻辑的处理。

6.4文本框提示

对于文本框的内容,如果输入的不正确,可对其进行提示

窗体文件如下

//文本框提示
import win.ui;
/*DSG{{*/
var winform = win.form(text="aardio form";right=455;bottom=231)
winform.add(
btnError={cls="button";text="错误";left=48;top=152;right=152;bottom=184;z=2};
btnInfo={cls="button";text="提示";left=304;top=152;right=400;bottom=184;z=4};
btnWarning={cls="button";text="警告";left=176;top=152;right=272;bottom=184;z=3};
edit={cls="edit";text="Edit";left=80;top=40;right=345;bottom=79;edge=1;multiline=1;z=1}
)
/*}}*/

winform.btnError.oncommand = function(id,event){
    winform.edit.showErrorTip("这是标题","这是要显示的错误信息")
}

winform.btnWarning.oncommand = function(id,event){
    winform.edit.showWarningTip("这是标题","这是要显示的错误信息")    
}

winform.btnInfo.oncommand = function(id,event){
    winform.edit.showInfoTip("这是标题","这是要显示的错误信息",true)    
}

winform.show();
win.loopMessage();

运行后点击错误按钮,文本框会显示错误的信息,其他的类型同理

6.5自定义气泡提示

有时组件不能满足需要,可进行自定义,这种组件需要指定坐标,这里以从屏幕右下角显示为例。

import winex.tooltip;

/*
不指定最后一个超时参数,则鼠标点击任意位置关闭。
参数 @2,@3 指定显示提示的 x,y 坐标,不指定坐标则取鼠标当前坐标。
参数 @1 指定要显示的内容,如果包含换行,则第一行显示为标题(同时显示关闭按钮)。
*/
winex.tooltip.balloon('系统提示\n这是提示内容,你看得见我吗?我会自动关闭',1800,1000,10000/*超时毫秒数*/);

win.loopMessage();

就是根据坐标设置提示框的位置。

6.6通知窗口

当有新消息时,也可以模仿操作系统的通知,弹出消息通知框。

先封装为一个组件messageInfo.aardio

//通知窗口 
import win.ui;
/*DSG{{*/
var winform = win.form(text="aardio form";right=271;bottom=127;bgcolor=15780518;border="none";exmode="toolwindow";parent=...;topmost=1)
winform.add(
static={cls="static";left=24;top=40;right=248;bottom=104;transparent=1;z=1}
)
/*}}*/

import win.util.popup
var info = ...;
//使窗口在屏幕右下角弹出
pop = win.util.popup(winform) 
pop.countdown=function(remaintime){
    winform.static.text = info;
    if(remaintime==0){
         winform.close();
    }
}

winform.show(true) 
win.loopMessage();
return winform;

然后调用

var messageInfo = loadcode("\function\popupinfo.aardio")
messageInfo("恭喜你,获取了一个红包")

运行后,就会在屏幕右下角弹出提示,10秒后自动关闭,不过默认的样式有点丑,具体可根据需要进行美化。

7.键盘的监听

如果想对键盘输入的内容进行处理后再返回,那就需要监听键盘(条形码的扫码枪也是一种输入设备,扫描条码后输出一串数字并回车)。

下面的案例是对键盘进行监听数字的输入:

  • 当输入类型是扫码枪时,输入的是数字并且回车后,才会显示数字(这里可以对输入的数字进行处理,比如扫码追溯码,将其转换为商品码),非数字不做处理,直接输出
  • 当输入类似是手工输入时,无论是数字或其他字符,都直接输出
import win.ui;
import winex;
import key;
import key.hook;
/*DSG{{*/
var winform = win.form(text="我的工具";right=555;bottom=175)
winform.add(
edit={cls="edit";left=48;top=16;right=496;bottom=96;edge=1;multiline=1;z=1};
static={cls="static";text="输入方式(F1):";left=48;top=128;right=128;bottom=152;transparent=1;z=2};
static2={cls="static";text="扫码枪";left=136;top=128;right=280;bottom=152;transparent=1;z=3}
)
/*}}*/


var arr={}//记录输入的数字
var hook = key.hook();
var keydown = {}//记录键按下
var isScanner = true;

//判断是否按了shift
isShift  =function(vkcode){
    return  vkcode==16 || vkcode==160 || vkcode==161 
}
//判断是否按下了某个键
isDownKey = function(vkcode,k){
    var rs = false;
    for(i=1;#keydown;1){
        var e = keydown[i];
        if(k=='shift'){
            if(isShift(e)){
                rs = true;
                break;
            }
        }
    }
    return rs;    
}


//键盘钩子:返回true表示禁用,返回false表示放行
hook.proc=function(msg,vkcode,scancode){ 
    var kname = key.getName(vkcode);            
    select(msg) {
        case 0x100/*_WM_KEYDOWN*/ ,0x104/*_WM_SYSKEYDOWN*/ {
            if(vkcode == 112/*F1,扫码枪和手工输入切换*/){
                isScanner = !isScanner;
                if(isScanner){
                    winform.static2.text="扫码枪";
                }else{
                    winform.static2.text="手工输入";
                }
            }
             
            var shiftDown = isShift(vkcode)
            if(shiftDown){
                //记录按下shift
                table.push(keydown,vkcode);
            }
             //记录输入的数字,有复合键时不处理
               if(#keydown==0){
                if ((vkcode >= 48 && vkcode <= 57 ) || (vkcode >= 96 && vkcode <= 105) ){
                        //对数字键盘进行处理,否则kname是NUMPAD1信息
                        if(vkcode >= 96 && vkcode <= 105)kname=vkcode-96
                         table.push(arr,kname);
                         //return ''可视为拦截了消息,然后通过winex.say发送新消息,否则不处理; 
                         if(isScanner)return '';
                     }
                     if(vkcode==13/*回车*/){
                         //清空按键按下的数组
                         table.clear(keydown)
                         if(isScanner){
                             //将数组转换为字符串
                             var strx = string.join(arr);
                             //获取当前窗口句柄
                             var hwndx = win.getForeground();    
                             //发送消息,这里可以对消息进行处理后再发送
                            winex.say(strx,hwndx);
                         }
                         table.clear(arr)    
                }
            }
        }
        case 0x101/*_WM_KEYUP*/,0x105/*_WM_SYSKEYUP*/ {
            //如果按下了shift
             var shiftDown  = isDownKey(vkcode,'shift')
               //是否弹起了shift
               var shiftUp = isShift(vkcode)
               /**对数字的输入有几种情况:
               1.没有按下shift 
               2.按下了shift并未弹起(组合键)
               3.按下了shift并且弹起了
               对于1和3可直接处理 清除按键按下的数组的shift记录,2不予处理。
            **/
            if(shiftDown && shiftUp) table.clear(keydown)
        }
    }
    return false;
}

winform.show() 
win.loopMessage();

上述的代码,看起来还是很简单的。截图如下:

一开始,我本想通过键盘钩子返回true和false来拦截并处理消息,但当返回true时,会禁止输入,会影响其他程序的正常使用,故更换了一种方式,就是在select中通过是否返回空字符来阻止消息的输出,可视为要阻止消息,那么在获取到消息后将其替换为空字符进行输出,在这个过程中对拦截的消息进行处理后再发送消息给操作系统。

8.菜单

一个普通的应用也是有菜单栏的,那么添加菜单也很简单,示例运行效果如下图

 

对应代码如下

//窗口菜单
import win.ui;
import win.ui.menu;
import win.dlg.message;
/*DSG{{*/
var winform = win.form(text="菜单用法演示";right=497;bottom=345;border="dialog frame";max=false;min=false;topmost=1)
winform.add()
/*}}*/

var t = 3*1000;//弹框关闭时间,3s//创建弹出菜单,可以在这里创建,也可以使用后面的主菜单的addTable()进行创建
var menuFile = win.ui.popmenu(winform);
/** add方法
    参数1 菜单名称
    参数2 function 可在里面执行代码
**/
menuFile.add("打开",function(id){
    winform.msgInfo("打开文件",t)
})
menuFile.add("保存",function(id){
    winform.msgInfo("保存文件咯",t)
})

var menuSystem = win.ui.popmenu(winform);
menuSystem.add("背景",function(id){
    winform.msgInfo("设置系统背景",t)
})
//除了使用add,也可以使用弹出菜单的addTable()进行创建
menuSystem.add(); //添加分隔线
menuSystem.addTable( {
    { "字体";function(id){
        createMenuFunction("\dlg\font.aardio");
    }};
    { /*---分隔线---*/ };
    { "退出"; function(id){
        winform.close() 
    }};
} )

//加载窗体文件
createMenuFunction = function(formPath){
    winform.show(false)
   win.loadForm(formPath)
} //创建主菜单,主菜单构建完成后要用menu.redraw()更新,menu.addTable()会自动调用redraw() var menu = win.ui.menu(winform); menu.add('文件',menuFile) menu.add('设置',menuSystem) menu.addTable({ { "帮助";{ {"关于";function(id){ createMenuFunction("\dlg\help.aardio"); }}; {"检查更新";function(id){ winform.msgbox("当前已是最新版本") }} }}; { "布局"; { { "横向排列"; function(id){ winform.msgInfo("横向排列",t) } }; {/*---分隔线---*/ }; { "竖向排列"; function(id){ winform.msgInfo("竖向排列",t) } } } }; } ) //设置只有一个选择的菜单 menu.add('隐藏(F10)',function(id){ winform.show(false); }); menu.add('关闭(F9)',function(id){ winform.close() }); winform.show() win.loopMessage();

关于代码引用的两个文件,自定义后指定正确的路径即可。

需要注意的是,在主界面打开子菜单时,会隐藏主界面,关闭子菜单时,会显示主界面,如果需要关闭时就能看到主界面,也就是主界面保持为当前最前的窗口,那么需要设置主界面窗口顶置,topmost=1,这个是属性里面也可以设置

9.程序托盘图标

一个应用程序,都有自己的图标,也会在任务栏创建托盘,以便在窗口隐藏或最小化时还能找到。下面创建了一个普通的托盘图标,先看效果图

上代码

import win.ui;
/*DSG{{*/
var winform = win.form(text="托盘图标";right=415;bottom=175;max=false)
winform.add(
static={cls="static";text="托盘图标的基本用法";left=136;top=64;right=408;bottom=88;notify=1;transparent=1;z=1}
)
/*}}*/
var isFront = true;//是否显示在最前面
//下面创建托盘图标 当设置程序的图标后(工程-属性-程序图标),就无须再指定托盘的图标,默认会使用程序的图标
import win.util.tray;
winform.tray = win.util.tray(winform)  

//设置鼠标提示 
winform.tray.tip = "百宝箱" 
//设置托盘消息通知
winform.tray.pop('恭喜你使用百宝箱,快来试试看吧',"消息通知");

//点击最小化按钮时触发
winform.onMinimize = function(lParam){
    winform.tray = win.util.tray(winform);
    winform.show(false); //隐藏窗口
    return true;//阻击默认消息传递,取消最小化过程
}
//托盘的消息处理
winform.onTrayMessage = {
    [0x205/*_WM_RBUTTONUP 单击右键*/  ] = function(wParam){ 
        //弹出托盘菜单以前,一定要前置主窗口中,避免不点击菜单不会消失,父窗口隐藏也要这样做
        win.setForeground(winform.hwnd)
          import win.ui.menu;
        
        winform.popmenu = win.ui.popmenu(winform);//创建弹出菜单
        winform.popmenu.add('退出',function(id){ winform.close() })        
                
        winform.popmenu.popup();
        winform.popmenu.close();
    };
    [0x202/*_WM_LBUTTONUP 单击左键*/] = function(wParam){ 
        if(isFront){
            winform.show(false);
            isFront = false;
        }else{
            winform.show(true);
            isFront = true;
        }
    };
    [0x203/*_WM_LBUTTONDBLCLK 双击左键*/] = function(wParam){};
    [0x404/*_PARAM_DESTROY*/] = function(wParam){};
    [0x405/*_PARAM_CLICKED*/] = function(wParam){};
}
winform.show() 
win.loopMessage();

对于图标,只需设计工程的图标即可,格式是一个icon的图片,设置截图如下:

需要说明的是,在上述的效果图中,通知时,最下面有一行的小字,这个小字就是程序的说明,由于此时并没有打包运行,故显示的是开发工具的名称,而打包后就会显示工程属性中的 "文件描述" 信息。

10.开机启动

很多时候,想要软件开机启动,则只需要将其加到操作系统的注册表中即可。

    import fsys;
    import win.reg;
    var exePath = fsys.getCurDir()+'\bbxClient.exe';        
    var reg = win.reg("HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run");
    reg.setValue('DrugstoreClient',exePath)//加入到注册表,相当于开机启动
    reg.delValue("DrugstoreClient");//删除,相当于不开机自启

把exe添加到用户启动注册表后,下次开机就会自启。