菜单

定时任务和异步线程

下载

前言

定时任务和异步线程都可以实现一个功能——能定时执行操作。下面着重来讲解他们的特性以及异同点。

区别

异同点

定时任务:可以顺序执行程序。 在 UI 线程中执行的操作可以在定时任务函数体中与 UI 交互。但是执行程序复杂,过程多会导致 UI 卡顿。
异步线程:可以顺序执行程序。 另开线程执行操作,只能进行变量控制,不能和 UI 交互。执行程序不会导致 UI 变卡。

ps:UI 操作即直接对页面的各个控件进行操作。

结论

因此,定时器更适合于操作简单,经常进行 UI 操作的过程。而异步线程适合操作复杂,可以用变量控制替代 UI 交互的过程

定时任务

页面定时任务

定时任务可以在页面中添加定时器控件,实现定时任务,也可以在全局中设置全局的定时任务,页面定时器如下图所示:


可以进行各种需要的设置。

次数限制

如果设置为 0 次表示不限制次数,>0 次表示次数为设定的次数。

系统定时任务

可以在工程设置中添加全局定时器。

这个定时器是开机即触发的,可以选择周期/触发两种调度方式。

异步线程

页面上的异步线程可以直接拖拽控件来实现,如下图所示


可以设置间隔时间,设置周期执行函数体,也可以编写结束时触发的函数。异步线程既可以执行一次,又可以执行多次。下面着重讲解一下如何在全局使用异步线程。

公共页使用

引入

首先,在公共页添加异步控件,生成异步事件

声明以便为全局所调用。

运行

单次调用

cpp 复制代码
void Frm04::wMAsyncWorker4_ref_cb(uint16_t code, LvEvent e) {
	/*复杂操作 网络连接 文件读写 ---*/
	//...
  func();
  wMAsyncWorker2->stop(); //结束执行
}

上面这种方法只能让函数体调用一次,如果想调用多次并进行定时,可以采用下面的写法方式,将 func()用 while 包裹起来

循环调用

c++ 复制代码
void Frm04::wMAsyncWorker4_ref_cb(uint16_t code, LvEvent e) {
	/*复杂操作 网络连接 文件读写 ---*/
  while (1){
    // 休眠一秒钟
    Util::sleepfor(1000);
    func();
  }
}

以上应用于全局(公共页)的异步线程,也可以以同样的方式应用于页面(例如放在页面的 onLoad,或者是各种控件的触发函数中~)。但是,在页面中不可与页面控件进行交互。

与控件交互

介绍

如果想与控件进行交互,可以采用变量作为中间介质进行触发,即 函数触发变量,变量触发控件
如下案例。

案例讲解

概要:页面 Frm01 中有个标签控件,需要实时将标签控件进行显示。

方法 1-直接绑定:

将标签控件绑定相应的变量,例如绑定变量名称为vvar,数据类型为整形;
在 func()里按下列代码所述配置即可

c++ 复制代码
void func(){
  // ....计算的一些操作
  // 计算为newVar
  vm->setInt("vvar",newVar);
}

方法 2-读取页面指针调用:

可以通过变量触发的方式。这种情况适用于间隔时间长的情况。在工程设置-普通型变量-添加变量触发函数。这种方式比较复杂,在遇到前后两次变量值相同的情况下就不会被触发。可以获取页面指针,使用页面中的方法。如下所示:

c++ 复制代码
// 获取页面指针后,曲线救国
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);

方法 3-在显示界面上加入定时器:

可以在页面上加入定时器,尽量设置更短的间隔时间(周期),如设置为 500ms,或者是 100ms 或者更低。
在我们之前描述的 func()中可以加上:

c++ 复制代码
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++中 λ 表达式的注意

在我们很多函数的回调中,采用了 c++的 λ(拉姆达)表达式,如异步线程的回调,弹出框的回调等。具体表现形式为[](){}

c++ 复制代码
worker->invoke([](){})->start();
pm->getLoginBox("登录")->onOk([](){})->show();

具体的详细的 λ 表达式的介绍还请参考 c++官方手册,下面仅讲解使用 ApusIDE 封装函数中最可能出现的问题。

c++ 复制代码
// 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();
最近修改: 2025-01-03Powered by