定时任务和异步线程都可以实现一个功能——能定时执行操作。下面着重来讲解他们的特性以及异同点。
定时任务:可以顺序执行程序。 在 UI 线程中执行的操作,可以在定时任务函数体中与 UI 交互。但是执行程序复杂,过程多会导致 UI 卡顿。
异步线程:可以顺序执行程序。 另开线程执行操作,只能进行变量控制,不能和 UI 交互。执行程序不会导致 UI 变卡。
ps:UI 操作即直接对页面的各个控件进行操作。
因此,定时器更适合于操作简单,经常进行 UI 操作的过程。而异步线程适合操作复杂,可以用变量控制替代 UI 交互的过程
定时任务可以在页面中添加定时器控件,实现定时任务,也可以在全局中设置全局的定时任务,页面定时器如下图所示:
可以进行各种需要的设置。
如果设置为 0 次表示不限制次数,>0 次表示次数为设定的次数。
可以在工程设置中添加全局定时器。
这个定时器是开机即触发的,可以选择周期/触发两种调度方式。
页面上的异步线程可以直接拖拽控件来实现,如下图所示
可以设置间隔时间,设置周期执行函数体,也可以编写结束时触发的函数。异步线程既可以执行一次,又可以执行多次。下面着重讲解一下如何在全局使用异步线程。
首先,在公共页添加异步控件,生成异步事件
声明以便为全局所调用。
void Frm04::wMAsyncWorker4_ref_cb(uint16_t code, LvEvent e) {
/*复杂操作 网络连接 文件读写 ---*/
//...
func();
wMAsyncWorker2->stop(); //结束执行
}
上面这种方法只能让函数体调用一次,如果想调用多次并进行定时,可以采用下面的写法方式,将 func()用 while 包裹起来
void Frm04::wMAsyncWorker4_ref_cb(uint16_t code, LvEvent e) {
/*复杂操作 网络连接 文件读写 ---*/
while (1){
// 休眠一秒钟
Util::sleepfor(1000);
func();
}
}
以上应用于全局(公共页)的异步线程,也可以以同样的方式应用于页面(例如放在页面的 onLoad,或者是各种控件的触发函数中~)。但是,在页面中不可与页面控件进行交互。
如果想与控件进行交互,可以采用变量作为中间介质进行触发,即 函数触发变量,变量触发控件
如下案例。
概要:页面 Frm01 中有个标签控件,需要实时将标签控件进行显示。
将标签控件绑定相应的变量,例如绑定变量名称为vvar
,数据类型为整形
;
在 func()里按下列代码所述配置即可
void func(){
// ....计算的一些操作
// 计算为newVar
vm->setInt("vvar",newVar);
}
可以通过变量触发的方式。这种情况适用于间隔时间长的情况。在工程设置-普通型变量-添加变量触发函数
。这种方式比较复杂,在遇到前后两次变量值相同的情况下就不会被触发。可以获取页面指针,使用页面中的方法。如下所示:
// 获取页面指针后,曲线救国
STTPage* mCurPagePtr = dynamic_cast<STTPage*>(pm->open("Frm01", PageMode::NEWWIN));
Frm01 *frm = dynamic_cast<Frm01*>(mCurPagePtr);
int newVar = 0;
vm->getInt("vvar",newVar);
frm->wMText->setText(newVar);
// 或者用这种方式读取页面指针
STTPage* mCurPagePtr = dynamic_cast<STTPage*>(getRuntime()->getIPageMgr()->getPage("Frm01"));
Frm01 *frm = dynamic_cast<Frm01*>(mCurPagePtr);
int newVar = 0;
vm->getInt("vvar",newVar);
frm->wMText->setText(newVar);
可以在页面上加入定时器,尽量设置更短的间隔时间(周期),如设置为 500ms,或者是 100ms 或者更低。
在我们之前描述的 func()中可以加上:
HmiApp.cpp
void func(){
// ....计算的一些操作
// 计算为newVar
vm->setInt("vvar",newVar);
// 加入一个标志位,记得先在hmiApp.hpp中进行定义
changeSignal = true;
}
Frm01.cpp
void Frm01::wMTimer1_timer_cb(uint16_t code, LvEvent e) {
if (hmiApp->changeData){
// 执行一些其他操作
int newVar = 0;
vm->getInt("vvar",newVar);
wMText->setText(newVar);
// 记得进行置位
hmiApp->changeSignal = false;
}
}
在我们很多函数的回调中,采用了 c++的 λ(拉姆达)表达式,如异步线程的回调,弹出框的回调等。具体表现形式为[](){}
。
worker->invoke([](){})->start();
pm->getLoginBox("登录")->onOk([](){})->show();
具体的详细的 λ 表达式的介绍还请参考 c++官方手册,下面仅讲解使用 ApusIDE 封装函数中最可能出现的问题。
// 1.想引用全局的变量(即所有变量)以异步线程操作函数为例
worker->invoke([&](){})->start();
// 2.想引用成员函数变量(以下引用不包含局部变量)
worker->invoke([this](){})->start();
// 包含局部变量
int varA;
worker->invoke([this,varA](){})->start();
// 3. 需要单独一个个引入变量
int varA,varB,varC;
worker->invoke([varA,varB,varC](){})->start();