原创作品,如需转载请注明出处
文章目录
1 简介
Control是一门内置于WinCCOA的脚本语言,语法结构类似C++
支持多线程
每个脚本中都有main()函数,脚本执行后进入main函数中
- 被动属性脚本
打开界面时对其main()函数处理一次,不一定与用户输入相关联,被动属性对过程状态进行可视化,包括图形边框颜色,可见性等等
可以理解为对象的属性
- 主动属性脚本
需要用户输入,比如:鼠标点击,单选框或者复选框等输入命令,
每点击一次就会执行一次脚本中的main函数,无需注册设备对象
可以理解为对象的方法
2 脚本触发方式
- 通过属性改变触发
函数绑定属性,当属性发生变化时,触发相应的函数,执行脚本
- 用户输入
比如:当我们点击一个按钮,触发脚本运行,这个脚本仅在点击一次按钮
- 2.3 终止脚本
关闭含有某个图形元素的运行界面,与图形元素相关的被动脚本将停止运行,
如果关闭了管理器(杀掉进程),所有启动脚本会被终止
3 寻址类型
- 寻址设备对象属性
A.:_original.._value
Pump12.Command_On:_original.._value
A.:_msg_conv.2._round_val
MySystem.:_pv_range.._min
- 寻址结构元素
Test_Structure.Fifthelement:_original.._value
Test_Structure[5]:_original.._value
- 使用别名寻址设备对象元素
Pump12.Command_On:_original.._value
@P12Com_On:_original.._value
Mausi1:Test_Structure.FifthElement:_original.._value
Mausi1:@T_Str5:_original.._value
在第一个示例中,“Pump12:Command_On”具有别名“P12Com_On”;在第二个示例中,“T+Str5”是“Test_Structure.FifthElement”的别名。
4 数据类型
名称 | 值范围 | 备注 |
---|---|---|
anytype | 任何类型,取决于第一个变量赋值 | |
atime | 报警时间,如多个报警同时触发,会为不同的报警设定索引以区分 | |
bit32 | 0~4294967295 | 位模式(32位) |
bit64 | 0~10146744073709551615 | 位模式(64位) |
blob | 二进制大对象 | |
bool | 0或1 true或fals | 二进制(1位) |
char | 0~255 | 字符(单字节) |
double | -1.79769e+308 to +1.79769e+308 | 64位浮点数 |
errClass | 指定错误类 | |
file | 文件指针 | |
float | -1.79769e+308 to +1.79769e+308 | 浮点数 = double |
function | 函数指针 | |
int | -2147483648 ~ +2147483647 | 整型值(32位) |
uint | 正整型值(32位) | |
long | 整型值64位 常量后缀要有L 0x7FFFFL | |
ulong | 整形值64位 常量后缀要有UL 0x7FFFFUL | |
langString | 语言字符串 | |
mixed | 与anytype相反,每次获得一个新类型 | |
mapping | 映射可保存任意键值对。键值对将包存在两个数组中 | |
va_list | 通过va_list可定义任意数目的参数。va_start将参数设置到va_list变量,va_arg类似一个迭代器,va_end停止参数列表的处理 | |
string | 任意数目的字符 | 字符串 |
time | 内部时间格式 | |
unsigned | 0~4294967295 | 正整型值 unsigned f=4294967295u; |
dyn_anytype | 任何数据类型的动态元素数组 | |
dyn_shape | 图形元素的动态指针数组。 | |
dyn_atime | atime 的动态数组。dyn_atime 包含 atime,因此,它是 DpIdentifier与带计数的时间的组合,其中包括配置和详细信息,但不包括 DPE,例如:":_alert_hdl.2" + 2009.08.12 19:11:54.356 (0) | |
dyn_bit32 | 动态位模式数组(32 位) | |
dyn_bit64 | 动态位模式数组(64 位) | |
dyn_blob | 动态 blob | |
dyn_bool | 二进制值的动态数组 | |
dyn_char | 动态字符数组 | |
dyn_errClass | WinCC OA 内部错误类的动态数组 | |
dyn_float | 浮点值的动态数组 | |
dyn_function | 函数指针动态数组 | |
dyn_int | 整型值的动态数组(32 位) | |
dyn_uint | 正整型值的动态数组(32 位) | |
dyn_long | 整型值的动态数组(64 位) | |
dyn_ulong | 正整型值的动态数组(64 位) | |
dyn_langString | 语言字符串的动态数组(请参见多语言功能) | |
dyn_mapping | 动态映射。映射可保存任意键/值对。键值对将保存在两个数组中。 | |
dyn_string | 字符串的动态数组 | |
dyn_time | 内部时间格式的值的动态数组 | |
dyn_dyn_anytype | 任何数据类型元素的动态数组的动态数组 | |
dyn_dyn_atime | 动态 atime 数组的动态数组 | |
dyn_dyn_bit32 | 动态位模式数组的动态数组(32 位) | |
dyn_dyn_bit64 | 动态位模式数组的动态数组(64 位) | |
dyn_dyn_blob | 动态 blob 数组 | |
dyn_dyn_bool | 二进制值动态数组的动态数组 | |
dyn_dyn_char | 动态字符数组的动态数组 | |
dyn_dyn_errClass | 动态错误类的动态数组 | |
dyn_dyn_float | 浮点值动态数组的动态数组 | |
dyn_dyn_function | 动态函数指针的动态数组 | |
dyn_dyn_int | 整型值动态数组的动态数组(32 位) | |
dyn_dyn_uint | 正整型值动态数组的动态数组(32 位) | |
dyn_dyn_long | 整型值动态数组的动态数组(64 位) | |
dyn_dyn_ulong | 正整型值动态数组的动态数组(64 位) | |
dyn_dyn_langString | 语言字符串动态数组的动态数组(请参见多语言功能) | |
dyn_dyn_shape | 图形元素动态指针的动态数组。 | |
dyn_dyn_string | 字符串动态数组的动态数组 | |
dyn_dyn_time | 内部时间格式的值数组的动态数组 | |
dbRecordset | ADO 接口的访问变量 | |
dbConnection | ADO 接口的访问变量 | |
dbCommand | ADO 接口的访问变量 | |
shape | 图形元素的指针 | |
idispatch | ActiveX 对象的方法的数据类型 |
下标访问法
位模式下使用pattern[i]访问每个位,对于bit32 i的范围是[0,31]返回bool
处理位运算的函数
字符串下使用string[i]访问每个字符,string[i]返回char
5 映射(关联数组)
5.1 基本概念
键 | 值 |
---|---|
“one” | 1 |
“two” | 2 |
“three” | 3 |
映射的作用:保存键值对
所有的键:放在一个数组中,所有的值放在另外一个数组中,所以也叫做关联数组
main(){
mapping m;
m["one"] = 1;
m["two"] = 2;
m["three"] = 3;
DebugN(m["one"]); // 输出: 1
}
映射可以嵌套
main(){
mapping m;
mapping n;
n["k1"] = "v1";
n["k2"] = "v2";
m["mk1"] = n;
DebugN(m["mk1"]["k1"]); // 输出”v1“
}
与dyn_string相比,映射占用空间大,写速度慢,读速度快
main(){
mapping root;
mapping child_map;
dyn_string child_dyn;
child_map["one"] = 1;
child_map["two"] = 2;
child_map["three"] = 3;
child_dyn[1] = "one";
child_dyn[2] = "two";
child_dyn[3] = "three";
root["c1"] = child_map;
root["c2"] = dyn_map;
DebugN("root->c1->element2"+root["c1"]["two"]); // 输出:2
DebugN("root->c2->element3"+root["c2][3]); // 输出: "three"
}
5.2 映射相关API
- 通过键直接修改/访问值
main(){
mapping m;
m["one"] = 1;
DebugN(m["one"]); //输出:1
m["one"] = 2;
DebugN(m["one"]); //输出:2
}
- 获取映射内共有多少对键值对 mappinglen
main(){
mapping m;
m["one"] = 1;
m["two"] = 2;
DebugN(mapping(m),"should be=2")
}
-
获取映射内所有key mappingKeys()
-
获取映射上索引的键 mappingGetKey()
for(int i = 1; i<=mappinglen(m); i++){
DebugN(mappingGetKey(m,i)); // 输出:k1,k2,...
}
-
获取映射上索引的值 mappingGetValue()
-
判断映射上有没有指定的键 mappingHasKey(mapping:m,string:“one”)
-
移除映射上的指定键 和键值 mappingRemove(mapping:m,string:“one”)
6 类型转换
数据类型转换过程中可能会有意想不到的结果
- 显示类型转换
int a = 123;
string s = "hello";
DebugN((string)a+s); //输出:hello 123
- 字符串转字节
string s = "00000011111100000011111100000011";
bit32 b = s;
string s = "FFAB003A";
blob b = s;
// 该 blob 现在包含 4 个字节,十六进制值为 FF、AB、00 和 3A。
// 字符串也可具有此形式
string s = "FF,AB,00,3A";
- 时间值与其他类型互转
7 变量和常量
- 变量名
字母或下划线开头,不限长度,区分大小写,推荐小驼峰命名:sayHelloWorld
- 默认值
control中每个变量即使不初始化变量,也有一个默认值,对于数值类型,int,float,double 默认值是0;对于字符变量char string 默认值为""
- 管理器全局变量
main()
{
...
addGlobal("counter", INT_VAR); // creation of the variable
counter=15; //counter can now be assigned a value
...
}
- 字符常量
‘x’ 单引号括起来的就是字符常量
- 数值常量
如果要显示大于 MAX_LONG 的值,则应使用无符号后缀
一般没有小数点的是int类型数值常量,十进制数,有小数点是float类型数值常量
字符串0开头,会被解析成八进制数,字符串以0X开头,会被解析成16进制数据
- 错误变量
errClass 存储错误信息:优先级,错误类型或错误文本。
-
未定义变量
如果运行时访问未定义的变量,则会报错,立即停止当前线程 -
“const”关键字
const用于将变量标记成常量,使用const修饰后的变量不支持修改
- 全局变量
main函数开头声明的变量在整个脚本/库内有效,如果脚本/库内其他函数含有同名变量,局部变量将覆盖全局变量
main(){
int a = 1;
int b = 2;
int add(){
int a = 4;
int b = 5;
return a+b;
}
int sum;
sum = add();
DebugN(sum); // 输出:9 而不是输出3
}
global 保留关键字
public 库内函数可以被调用
private 库内函数不能被外部程序调用,只能自己调用
8 运算符
8.1 算术运算符
// 二元运算符
// + - * / %
// % 求余运算符不能用于浮点数
// + - 运算符才可用于时间值
time t1, t2;
t1 = t1 - 3600; // 简写 t1 -= 3600 t1减小1小时
8.2 递增/递减运算符
// ++ 自增运算发
// -- 自减运算符
// ++a 在使用a变量之前对a变量加1
// a++ 在使用a变量之后对a变量加1
main()
{
int a, b, d;
a = 3;
b = 5;
d=a*b++;
DebugN(d); //++b 的结果 = 18,而 b++ 的结果 = 15
DebugN(b); //结果总是 = 6
}
8.3 条件运算符
// expr1? expr2 :expr3;
// 判断expr1表达式的值,如果为true执行expr2,如果为false执行expr3,返回值是expr2或者expr3表达式返回的值
main(){
int a,b;
a = 1; b =2;
int res;
res = (a>b) ? a*10 : b*10;
DebugN(res); // 20
}
// expr2和expr3表达式一定要返回相同的数据类型
8.4 关系运算符和逻辑运算符
// > >= < <= == !=
// && || !
8.5 位运算符和移位运算符
// & 位与运算符
// 1 & 1 = 1
// 1 & 0 = 0
// | 位或运算符
// ~ 位非运算符
// ^ 位异或运算符 相同为0 相异为1
// << 左移移位运算符 1 << 2 返回 100
// >> 右移移位运算符 00100 >> 1 返回 00010
main()
{
bit32 Test;
Test=0x8FFFFFFFU;
DebugN("Firstly",Test);
Test=Test>>16u;
DebugN("Secondly",Test);
}
8.6 赋值运算符
左侧的变量将在右侧最开始处重复。可用更紧凑的形式来书写该表达式:i += 2
// 多重赋值
tag1 = tag2 = tag3 = 1;// tag3=1 tag1和tag2没有赋到值
main()
{
setMultiValue("RECTANGLE1", "visible", bVisible, "RECTANGLE2", "visible", bVisible, "RECTANGLE3", "visible", bVisible);
}
9 控制结构
9.1 if-else
main(){
int a,b;
a = 1; b=2;
if(a>b){
DebugN("a>b");
}
else{
DebugN("a<b");
}
}
// if...else... 支持嵌套使用
9.2 switch
main(){
int y;
switch(y){
case 1:DebugN("Monday");
break;
case 2:DebugN("Thusday");
braek;
default:
DebugN("error");
}
}
9.3 while
// 1~100 的和
main(){
int sum = 0;
int i = 0;
while(i<=100){
sum += i;
i ++ ;
}
DebugN(sum);
}
9.4 do… while…
// 1~100加和
main(){
int i = 0;
int sum = 0 ;
do{
sum = sum + i;
i ++;
}
while(i<=100);
DebugN(sum);
}
do…while… 和while的区别是do…while语句至少执行一次,while语句不满足条件一次都会执行
9.5 for循环
// for语法
/*
for(expr1;expr2;expr3;){
循环体;
}
*/
// 1-for循环计算0~100加和
main(){
int sum = 0;
for(int i=0;i<=100;i++){
sum+=i;
}
DebugN(sum);
}
// 2-for死循环方式1
main(){
for(;;){
DebugN("loop always");
}
}
// 3-for死循环方式2
main(){
for(int i=0;i<10;){
DebugN("loop always");
}
}
9.6 break&continue
main(){
mapping m;
m["one"] = 1;
m["two"] = 2;
m["three"] = 3;
for(int i=0;i<mappinglen(m);i++){
if (mappingGetKey(m,i) == "one"){
continue;
}
DebugN(mappingGetKey(m,i));
}
}
/*
输出:
"two"
"three"
*/
main(){
mapping m;
m["one"] = 1;
m["two"] = 2;
m["three"] = 3;
for(int i=0;i<mappinglen(m);i++){
if (mappingGetKey(m,i) == "three"){
break;
}
DebugN(mappingGetKey(m,i));
}
}
/*
输出:
"one"
"two"
*/
9.7 try…catch/finally-throw
try-catch 语句可以捕获由 throw() 显式抛出的异常或由脚本错误(例如,未声明的变量、索引超出范围、被零除等)引发的异常。
“被试验”并最终引发异常的代码/语句是在一个 try 块中定义的。如果在执行这些语句过程中发生异常,则执行一个 catch 块或 finally 块。
try 块的后面必须跟有一个 catch 块、一个 finally 或这两个块(以 catch-finally 的顺序)。
catch 块可捕获异常并将其删除。如果还另外跟有一个 finally 块,则在将在 catch 块的后面执行该块。如果没有该块,则将处理 try 块中尚未执行的语句。
finally 块将独立执行,而不管是引发了异常还是提供了 catch 块。随后,在应执行特定代码的每种情况下(如变量重置),finally 块都十分有用,即使此时无法对异常进行处理。
throw(errClass e) 函数会抛出异常 (‘e’)。异常的类型总是 errClass。.
finally-/catch块中的 异常
如果 finally 块中发生异常,则会取消处理,该块继续“前滚”,直到发现下一个 try-catch//finally 块。一个异常总是会由最新/当前异常所取代。
如果在 catch 块中发生异常,则会取消处理,但最终将在对该块“前滚”之前执行现有的 finally 块,以便找到新的 try-catch/-finally 块。一个异常总是会由最新/实际异常所取代。
如果在“前滚”过程中未找到其它 try-catch/-finally 块,则该线程将退出并返回错误消息(“uncaught exception …”)。
main()
{
try
{
DebugN("main:try");
throw(makeError("", PRIO_SEVERE, ERR_PARAM, 54, "In main:try"));
foo();
DebugN("main:try end");
}
catch
{
DebugN("main:catch");
DebugN(getLastException());
//抛出(makeError("", PRIO_SEVERE, ERR_PARAM, 54, "In main:catch"));
DebugN("main:catch end");
}
finally
{
DebugN("main:finally");
//抛出(makeError("", PRIO_SEVERE, ERR_PARAM, 54, "In main:finally"));
DebugN("main:finally end");
}
DebugN("main:end");
}
foo()
{
try
{
DebugN("foo:try");
throw(makeError("", PRIO_SEVERE, ERR_PARAM, 54, "In foo:try"));
DebugN("foo:try end");
}
finally
{
DebugN("foo:finally");
//抛出(makeError("", PRIO_SEVERE, ERR_PARAM, 54, "In foo:finally"));
DebugN("foo:finally end");
}
DebugN("foo:end");
}
未完待续
原创作品,如需转载请注明出处