脚本编写的规则与技巧

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;

脚本中定义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

//字体资源栏,每个字体有单独的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显示

Bit位

比特(Bit):

比特是计算机中最小的数据单位,只能存储两种状态:0 或 1。

通常用来表示二进制位。

例如,5的二级制数为00000101。大多数情况下,比特位的计数是从0开始的,即最右边的比特位是第0位,最左边的比特位是第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的位置,再按位与上1。

按位与、按位或配合使用,控制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(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.函数的应用

8.自定义函数