脚本编写的规则与技巧

1.脚本编写的位置

串口屏脚本是实现功能的重要方式,只需要掌握一点基础的C语言知识,了解我们屏幕的脚本编写规则,就能实现各种功能。

1.1 可见控件下的脚本

此类脚本是最常见和常用的

例如:一个普通按钮控件下的 按下事件弹起事件

按下事件:当按下按钮时,执行一次按下事件里面的脚本;

弹起事件:当松开按钮时,执行一次弹起事件里面的脚本;

img

  • 除了按钮控件有按下弹起事件外,还有:整数控件、浮点数控件、文本控件、触摸热区控件都有按下弹起事件,这些控件脚本执行逻辑和按钮控件一样。

  • 双态按钮控件,也属于按钮的一种,可看作一个开关控件,点击后松开执行一次按下事件的脚本,再次点击后松开执行一次弹起事件的脚本。

  • 单选控件、多选控件、滑块控件,都有一个值改变事件,当控件的选中值变化时,则会执行其控件下的脚本。

1.2 不可见控件下的脚本

常见于协议处理控件、定时器控件、音频控件等

不可见控件:拖入显示设计区域后,没有实际控件显示,而是在显示区域下方; img

  • 协议解析类控件,会在屏幕串口接收到数据时,执行控件下的脚本,每接收一次就执行一次。

  • 定时器控件,在打开定时器后(勾选en属性),会以一个间隔时间循环执行里面的脚本。

  • 音频控件的播放完成事件,会在音频播放完成后执行里面的脚本。

1.3 页面事件脚本

分为 页面加载事件 和 页面离开事件

每个页面都会有加载和离开两个动作事件,都是在加载页面和离开页面时,执行一次里面的脚本。 img

  • 通常在页面加载和离开事件里做一些初始化的操作。

备注

  • 在多行脚本的中间某行,插入一个翻页的操作,翻页操作后面的脚本会在跳转到其他页面后继续执行,直至执行完所有脚本。

  • 在多行脚本的中间某行,插入一个关闭定时器的操作,定时器关闭后会继续执行剩余的脚本,而不是等待定时器内脚本执行完后再执行剩余的脚本。

  • 脚本的执行顺序:触发某事件后,由第一行依次执行代码直至最后一行。

小技巧

脚本编辑区的三个功能:img

  • 脚本搜索:用于在当前脚本区域检索指定的内容,脚本很多时方便定位。

  • 编辑区锁定:有锁定和解锁两种状态。当锁定时,脚本编辑区会锚定所选的控件,点击其他控件,脚本编辑区不会切换过去,免去了频繁的切换。

  • 编辑区放大:可以将编辑区窗口放大至全屏,便于编辑脚本,配合锁定功能食用,效果更佳。

2.关键字

目前支持的关键字(未提到的则不支持):

控制结构关键字:

if:条件判断语句,用于执行基于条件的不同分支。

else:与 if 结合使用,用于在条件不成立时执行另一段代码。

while:循环语句,用于重复执行一段代码直到条件不满足。

do:循环语句,与 while 结合使用,保证循环体至少执行一次。

for:循环语句,用于重复执行一段代码,可以同时初始化、测试和更新循环变量。

break:跳出当前循环。

continue:跳过当前循环体中的剩余代码,继续下一次循环。


数据类型关键字:

void:表示没有类型或不确定类型,常用于函数声明中表示无返回值。

int:整型数据类型。

float:单精度浮点类型。


其他关键字:

return:用于从函数中返回值。


3.变量的定义

3.1 脚本中定义变量

脚本代码中支持定义变量:int、float、byte,脚本中定义的都为局部变量,作用域为当前脚本代码编辑区,临时变量无法跨控件脚本使用,例如:在按钮控件下定义的临时变量int i = 10;,无法在其他控件的脚本下去调用变量 i。同样的,如按钮控件的按下事件里定义的变量,无法在弹起事件里调用。

脚本中定义int型:

//支持的写法:
int a;
int b = 123;
a = 666;

//不支持的写法:
int a , b;
int a , b = 123;

脚本中定义float型:

//支持的写法:
float f;
float f1 = 1.23;
f = 3.14;

//不支持的写法:
float f , f1;
float f , f1 = 1.23;

备注

  • int:带符号 32 位整型。

  • float:带符号 32 位单精度浮点型。

脚本中定义byte型数组:

//支持的写法:
byte arr[5] = {0x01 , 0x02 , 0x03 , 0x04 , 0x05};
byte a[5];
a[0] = 0x01;
a[1] = 0x02;
a[2] = 0x03;
a[3] = 0x04;
a[4] = 0x05;

//将某个整数控件的显示值赋给数组某个元素(int型不能直接赋值给byte型,所以用强制转换处理)
a[4] = (byte)num1.val;

脚本中定义int型数组:

//支持的写法:
int a[5] = {0x01 , 0x02 , 0x03 , 0x04 , 0x05};
int b[5] = {1 , 2 , 3 , 4 , 5};
int c[5];
c[0] = 1;
c[1] = 2;
c[2] = 3;
c[3] = 4;
c[4] = 5;

//将某个整数控件的显示值赋给数组某个元素
c[4] = num1.val;

脚本中定义float型数组:

//支持的写法:
float f[5] = {1.1 , 2.1 , 3.1 , 4.1 , 5.1};
float f1[5];
f1[0] = 1.1;
f1[1] = 2.1;
f1[2] = 3.1;
f1[3] = 4.1;
f1[4] = 5.1;

//将某个浮点数控件的显示值赋给数组某个元素
f1[4] = numf1.valf;

需要注意,脚本中变量的定义必须在最前面,否则会编译报错。

正确:定义在赋值语句前面 img

错误:定义在赋值语句中间 img


3.2 变量控件

脚本中定义的变量都为局部变量,而要实现全局变量,就需要用变量控件img

变量控件为不可见控件,拖入后会以控件名的形式存在于设计面板下方: img

选中变量控件,可在右侧属性栏设置:

  • 勾选global属性后,可全局使用(整个工程都可调用),变量控件下无法写脚本,只能被调用。

    跨页调用控件属性时,需加上控件所在页面的页名称,如:page1.var2.val = 123;表示给page1页面的var2控件赋值123。

  • type属性:定义此变量控件的变量类型。

当type选择Int:

var2.val = 123;//赋值

num1.val = var2.val;//取值,用整数控件num1显示

当type选择Float:

var2.valf = 3.14;//赋值

numf2.valf = var2.valf;//取值,用浮点数控件numf2显示

当type选择String:

var2.txt = "";//赋空值

var2.txt = "ABC123";//赋值字符串,注意双引号必须为英文引号

text3.txt = var2.txt;//取值,用文本控件text3显示

String类型变量无法在脚本中直接定义,所以用变量控件实现,或者用文本控件。

备注

  • type属性选择Int/Float/String时,对应的值属性为val/valf/txt,若设置的类型和调用的值属性不一致,则会编译报错。

  • Int/Float/String三种类型的变量,可以用整数控件/浮点数控件/文本控件对应代替。


3.3 数组控件

脚本中定义的数组只限制于局部使用,而要实现全局使用,就需要用数组控件img

数组控件为不可见控件,拖入后会以控件名的形式存在于设计面板下方: img

选中数组控件,可在右侧属性栏设置:

  • 勾选global属性后,可全局使用(整个工程都可调用),数组控件下无法写脚本,只能被调用。

  • type属性:定义此数组控件的数据类型。

type 属性选择 Byte 时:

赋值:arr3.valbs[0] = 0x64; 或者 arr3.valbs[0] = 100;

读取:num1.val = arr3.valbs[0]; //读出用整数控件 num1 显示,显示值为 100

清除:arr3.clear(0,10); //清除从下标 0 开始,向后的 10 个元素


type 属性选择 Int 时:

赋值:arr3.vals[0] = 0x64; 或者 arr3.vals[0] = 100;

读取:num1.val = arr3.vals[0]; //读出用整数控件 num1 显示,显示值为 100

清除:arr3.clear(0,10); //清除从下标 0 开始,向后的 10 个元素


type 属性选择 Float 时:

赋值:arr3.valfs[0] = 100.0;

读取:numf1.valf = arr3.valfs[0]; //读出用浮点数控件 numf1 显示,显示值为 100.0

清除:arr3.clear(0,10); //清除从下标 0 开始,向后的 10 个元素


type 属性选择 String 时,需要用控件的方法函数:

赋值:arr3.set(0,"txt123"); //赋值字符串"txt123"

读取:text1.txt = arr3.get(0); //读出用文本控件 text1 显示,显示值为"txt123"

清除:arr3.clear(0,10); //清除从下标 0 开始,向后的 10 个元素

备注

  • 目前只支持一维数组。且只支持上述类型。

  • 可在属性面板设置数组长度,数组控件的元素索引都是从0开始。

  • type属性选择Byte/Int/Float/String时,对应的值属性为valbs/val/valf/方法函数,若设置的类型和调用的值属性不一致,则会编译报错。

  • 考虑到Byte型和Int型之间相互赋值的问题,目前支持的强制转换:(byte)、(int)。

  • 勾选数组控件的global属性后,可全局使用,跨页调用控件属性时,需加上控件所在页面的页名称,如:page1.arr3.vals[1] = 0x64;表示给page1页面的数组控件arr3的第二个元素赋值0x64。

4.控件属性赋值

对控件的操作,就是调用控件属性。

4.1 控件属性的调用方式

三易串口屏有固定的调用属性方式:控件名.属性名

使用:在脚本中输入实际的控件名称(控件的name属性),然后用符号‘ . ’去定位使用某个属性。

例如:拖入一个整数控件,名称为num1,让控件显示整数‘123’的脚本为num1.val = 123;,这里调用了控件的值属性‘val’。

img

编写脚本时,注意使用所拖入控件的实际名称。

4.2 常用属性调用举例

控件的位置:

num1.x = 10;//x值

num1.y = 20;//y值

//x、y属性,可实现弹出类功能,或者连续改变坐标值实现移动效果

//当x、y值大于串口屏实际分辨率时,控件会位于显示区域之外,达到‘隐藏’效果

控件的大小:

num1.width = 60;//控件的宽度

num1.height = 60;//控件的高度

控件的显示与隐藏:

num1.visible = 0;//控件隐藏

num1.visible = 1;//控件显示

//visible属性,通常用来实现提示功能或选择功能

//visible属性,赋值0时为隐藏,非0时都是显示

控件的透明度:

num1.opacity = 0;//控件透明度为0(最小值,完全透明看不见)

num1.opacity = 100;//透明度为100(最大值,完全显示)

//opacity属性,目前G系列不支持

颜色的相关属性:

num1.fontColor = 0xFF000000;//设置控件显示的字体为黑色

num1.bgColor = 0xFF00FF00;//设置控件的背景色为绿色(前提是控件属性中设置的背景类型为颜色)

page0.bgColor = 0xFF00FF00;//设置page0页面的背景色为蓝色(前提是页面属性中设置的背景类型为颜色)

//颜色相关属性,赋值格式为:0xFF+颜色的hex代码

图片的相关属性:

num1.bgImg = user.image.p1;//设置控件的背景为图片p1(前提是控件属性中设置的背景类型为图片)

num1.bgImg = 1;//设置控件的背景为id是1的图片(图片资源栏中,每张图片都有独自的id)

page0.bgImg = user.image.p1;//设置page0页面的背景为图片p1(前提是页面属性中设置的背景类型为图片)

//上述介绍了两种调用图片的方式,推荐使用:user.image.图片名称,调用图片id的方法可能因为图片资源的增删而导致显示出错

//图片名称需要使用:字母和数字的命名组合,才能在脚本中调用

字体的相关属性:

num1.font = 1;//num1控件使用字体id为1的字体

//字体资源栏,每个字体有单独的id,脚本中去更换某个控件使用的字体时,直接赋值id号

赋显示值的相关属性:

num1.val = 123;//给整数控件num1赋值显示123

numf1.valf = 3.14;//给浮点数控件numf1赋值显示3.14

text1.txt = "ABC123";//给文本控件text1赋值显示字符串"ABC123"

text1.txt = "ABC"+"123";//给文本控件text1赋值显示字符串"ABC123"

text1.txt = text2.txt + text3.txt;//将text2和text3的显示字符拼接起来给text1

text1.txt = "\"ABC123\"";//输出带双引号的字符串,需要用到转义字符 \"

//字体资源栏,每个字体有单独的id,脚本中去更换某个控件使用的字体时,直接赋值id号

备注

  • 上述举例使用的整数控件num1,编写脚本时请使用所拖入控件的实际名称。

  • 上述举例的属性为可见控件所有,控件实际的属性需选中控件后在属性面板查看。

  • 注意控件属性有可读写和只读写的区别,脚本调用时会有汉字提示;所有控件的name属性,都为只读,不可脚本内修改。

跨页面调用控件属性:

//跨页调用控件属性的前提条件:必须勾选控件的global属性,否则会编译报错

page2.num1.val = 123;//给page2页面中的num1控件赋值123

page3.num3.x = 50;//将page3页面中的num3控件横坐标x值改为50

//对于没有global属性的控件(例如协议解析类的控件),可以直接全局调用

定时器的属性:

//勾选控件的global属性后会全局运行,否则只在当前页面运行

timer1.en = 0;//关闭定时器(1:打开定时器)

//若在定时器运行过程中关闭定时器(执行到某行脚本时关闭),定时器会在执行完后续所有脚本后关闭

备注

  • 因为控件和对应属性较多,无法一一列举,以上列举的属性为部分常用属性作为参考,更多介绍请参考控件的介绍和使用

5.运算符

5.1 支持的运算符

算术运算符

运算符

描述

示例

+

加法

a + b

-

减法

a - b

*

乘法

a * b

/

除法

a / b

%

取模(求余数)

a % b

关系运算符

运算符

描述

示例

==

等于

a == b

!=

不等于

a != b

<

小于

a < b

>

大于

a > b

<=

小于等于

a <= b

>=

大于等于

a >= b

逻辑运算符

运算符

描述

示例

&&

逻辑与(AND)

a && b

||

逻辑或(OR)

a || b

!

逻辑非(NOT)

!a

位运算符

运算符

描述

示例

&

按位与

a & b

|

按位或

a | b

^

按位异或

a ^ b

~

按位取反

~a

<<

左移

a << b

>>

右移

a >> b

赋值运算符

运算符

描述

示例

=

简单赋值

a = b

+=

加法赋值

a += b 等同于 a = a + b

-=

减法赋值

a -= b 等同于 a = a - b

*=

乘法赋值

a *= b 等同于 a = a * b

/=

除法赋值

a /= b 等同于 a = a / b

%=

取模赋值

a %= b 等同于 a = a % b

&=

按位与赋值

a &= b 等同于 a = a & b

|=

按位或赋值

a |= b 等同于 a = a | b

^=

按位异或赋值

a ^= b 等同于 a = a ^ b

<<=

左移赋值

a <<= b 等同于 a = a << b

>>=

右移赋值

a >>= b 等同于 a = a >> b

备注

  • 上述运算符优先级关系同C语言。

5.2 运算符的使用

基础的加减乘除大于小于一类的不做介绍,这里着重介绍一下移位的相关写法。

多字节拼接

在处理协议数据的时候,经常会碰到两个甚至多个字节来传递数据的情况。

例如,串口屏的协议解析器控件 protocol3 收到一帧6字节hex数据:0A 0B 12 13 14 05,收到后会以数组形式缓存在protocol3.rxBuf属性中。

//基础知识:1 字节(Byte) = 8 比特(Bits)

num1.val = (protocol3.rxBuf[0] << 8) | protocol3.rxBuf[1];//将0A 0B 两个字节拼接成一个数给num1显示

num1.val = (protocol3.rxBuf[2] << 16) | (protocol3.rxBuf[3] << 8) | protocol3.rxBuf[4];//将12 13 14 三个字节拼接成一个数给num1显示

备注

  • 移位的操作方式同C语言。

Bit位

比特(Bit):比特是计算机中最小的数据单位,只能存储两种状态:0 或 1。通常用来表示二进制位。

例如,5的二进制数为00000101。大多数情况下,比特位的计数是从0开始的,即最右边的比特位是第0位(bit0),最左边的比特位是第7位

if((5 & 0x01) != 0)//判断bit0,若为1,则会进入if,若为0,则进入else
{
  text1.txt = "打开";
}else
{
  text1.txt = "关闭";
}

判断一个数的某个bit位状态,只需要按位与固定的值

比特位

二进制表示

十六进制值

bit0

00000001

0x01

bit1

00000010

0x02

bit2

00000100

0x04

bit3

00001000

0x08

bit4

00010000

0x10

bit5

00100000

0x20

bit6

01000000

0x40

bit7

10000000

0x80

...

...

...

所以,若需要判断bit6的状态:

if((5 & 0x40) != 0)//判断bit6,若为1,则会进入if,若为0,则进入else
{
  text1.txt = "打开";
}else
{
  text1.txt = "关闭";
}

备注

  • 能实现判断bit状态的写法有很多种,例如还可以通过右移>>将需要判断的bit移到bit0的位置,再按位与上0x01。

按位与、按位或配合使用,控制bit位状态的改变:

num1.val = num1.val & 0xFE;//bit 0 置0
num1.val = num1.val | 0x01;//bit 0 置1

num1.val = num1.val & 0xFD;//bit 1 置0
num1.val = num1.val | 0x02;//bit 1 置1

num1.val = num1.val & 0xFB;//bit 2 置0
num1.val = num1.val | 0x04;//bit 2 置1

num1.val = num1.val & 0xF7;//bit 3 置0
num1.val = num1.val | 0x08;//bit 3 置1

num1.val = num1.val & 0xEF;//bit 4 置0
num1.val = num1.val | 0x10;//bit 4 置1

num1.val = num1.val & 0xDF;//bit 5 置0
num1.val = num1.val | 0x20;//bit 5 置1

num1.val = num1.val & 0xBF;//bit 6 置0
num1.val = num1.val | 0x40;//bit 6 置1

num1.val = num1.val & 0x7F;//bit 7 置0
num1.val = num1.val | 0x80;//bit 7 置1

6.逻辑语句

6.1 if语句

if语句形式:

if(条件表达式) 
{ 
  //一个或多个语句
}
//用法1:判断数值
if(num1.val == 1)//若整数控件显示的值为1,则文本控件text1显示正确
{
  text1.txt = "正确!";
}

//用法2:判断字符串
if(text1.txt == "打开")//若文本控件text1显示的“打开”,则改变显示为“关闭”
{
  text1.txt = "关闭";
}

//用法3:判断图片
if(num1.bgImg = user.image.p1)//若整数控件显示的背景图片为p1,则改变背景图片显示为p2(前提条件为控件属性中背景类型选择且绑定的图片)
{
  num1.bgImg = user.image.p2;
}

//用法4:判断颜色
if(num1.bgColor == 0xFF000000)//若整数控件显示的背景颜色为黑色,则改变背景颜色显示为白色(前提条件为控件属性中背景类型选择的颜色)
{
  num1.bgColor = 0xFFffffff;
}

//用法5:配合关系运算符使用
if(num1.val >= num2.val)//若num1的值大于等于num2的值,则num3加1
{
  num3.val++;
}

//用法6:配合逻辑运算符使用
if((num1.val > 100) && (num1.val < 200))//若num1的值大于100,且小于200,则num3减1
{
  num3.val--;
}

if else 语句形式:

if(条件表达式) 
{ 
  //一个或多个语句
}else
{
  //一个或多个语句
}
if(num1.val == 1) //若满足if的判断条件,则进入if分支,否则进入else
{ 
  num1.val = 2;
}else
{
  num1.val = 3;
}

if(num1.val == 1) //若满足if的判断条件,则进入if分支,否则判断下一个if是否满足
{ 
  num1.val = 2;
}else if(num1.val == 2)
{
  num1.val = 3;
}else
{
   num1.val = 0;
}

if(num1.val == 1)//if语句的嵌套使用
{
  if(num2.val == 1)
  {
    num1.val = 2;
  }else
  {
    num1.val = 3;
  }
}else
{
  num1.val = 0;
}

6.2 for语句

for语句:

//用于重复执行一段代码,通常用于已知迭代次数的情况

for(赋值表达式; 条件表达式; 赋值表达式)
{ 
  //一个或多个语句
}
int i;
num1.val = 1;

//使用for循环计算10的阶乘,并用整数控件num1显示结果
for (i=1;i<=10;i++) 
{
  num1.val *= i;
}

//同样的,for语句也支持嵌套使用

6.3 while语句

while语句:

//用于重复执行一段代码,通常用于未知迭代次数的情况

while(条件表达式) 
{ 
  //一个或多个语句
}
int i;
num1.val = 1;

//使用while循环计算10的阶乘,并用整数控件num1显示结果
while (i <= 10) 
{
  num1.val *= i;
  i++;
}

6.4 do while语句

//用于重复执行一段代码,至少执行一次,即使条件一开始就不满足

do 
{
  num1.val++;
}while (num1.val < 50);//当num1自增到50时,循环停止

6.5 break 语句

//用于立即退出循环

int i;
for(i=0;i<100;i++) 
{
  if (i == 50) 
  {
    break;
  }
  num1.val = i;
}

7.函数的应用

7.1 串口屏内置函数

为了方便用户实现某些功能,我们在串口屏中内置了丰富的函数,使得开发更高效。

7.2 函数的调用

函数的介绍和用法章节列举了所有的内置函数,方便用户查找使用。

此处列举几个函数的使用方式:

  • 翻页函数 – void showPage(int a);

void:函数执行后无返回值

a:页的id号

此函数通常写在某个按钮的按下事件或者弹起事件中,实现点击按钮后翻页的功能。示例:

showPage(2);//跳转到页id为2的页面

showPage(num1.val);//参数可为一个int型变量,若是一个不存在的页面id值,则脚本执行无效
  • 外发字符串函数 – void uartSend(string a);

void:函数执行后无返回值

a:需要发送的字符串

脚本中调用执行后,会通过串口将指定的字符串外发出去,示例:

uartSend("text1.txt");//发送文本控件text1显示的字符

uartSend("ABcd123");//发送“ABcd123”字符串

函数体内可嵌套其他函数:

uartSend( intToString(num1.val) );//将整数控件nu1的值转换为字符串,然后再将字符串发送出去

  • 后退格函数 – string stringTrimEnd(string s,int count);

string:函数执行后会返回一个新的字符串

s:字符串

count:移除的字符数量

示例:

text1.txt ="123456";

text2.txt = stringTrimEnd(var1.txt, 3);//移除字符串的后3个字符,文本控件text2显示“123”。

8.自定义函数

8.1 函数的定义

一个典型的C语言函数包含以下几个部分:

  • 返回类型:指明函数返回值的数据类型。如果函数不返回任何值,则使用关键字void。

  • 函数名:标识函数的名称。

  • 参数列表:包含传递给函数的参数的声明,包括参数的数量和类型。

  • 函数体:包含执行的代码块,即函数要执行的具体操作。

返回类型 函数名(类型说明 变量名,类型说明 变量名,…)

{

函数体;//一条或多条语句

}

定义:

打开VP上位机,左上角菜单栏,工具菜单,进入函数编辑器。

img

函数体内操作控件属性时,需要勾选被调用控件的global属性,并且加上控件所在页的页面名称。

编辑完脚本后,先点击左下方的测试按钮,保证函数无误(即找到 n 个函数),然后点击确定退出。

注意:

1.函数体内操作控件属性时,需要控件勾选 global 属性,并且加上控件所在页的页名称;

2.函数之间都是平行的,无主函数子函数的区别,不支持嵌套定义;

3.自定义函数目前支持的返回类型:void、int、float、string、byte;

函数编辑器面板的测试、应用、确定: img

测试:函数定义编辑完成后,点击测试,若无语法规则错误,则会提示成功;同时也会保存窗口内脚本;

应用:当测试无误后,点击应用,可在不关闭编辑器窗口的情况下,在VP页面中调用,以避免定义和使用时频繁操作编辑器页面;

确定:测试无误后,点击确定,完成函数的定义,关闭窗口;

8.2 函数的调用

img

1.在某个脚本事件中输入函数调用,且可在任意页面不限次数调用;

2.可用控件属性值作实际参数,传递给函数(必须符合函数定义的参数类型);

3.自定义函数的参数,可调用其他内置/自定义函数;

9.脚本注释

单行注释:

//text3.txt = “123”;

多行注释:

/*text3.txt = “123”;

text3.txt = “456”;*/