awtk/docs/how_to_non_gui_thread_operate_widget.md

127 lines
3.8 KiB
Markdown
Raw Normal View History

2020-04-09 12:25:12 +08:00
## 如何在非 GUI 线程操作 GUI 控件
2018-05-18 18:14:15 +08:00
GUI 控件只能在 GUI 线程进行操作,非 GUI 线程想操作 GUI 控件,必须用以下函数进行串行化。
### 1. idle\_queue
idle\_queue 向主循环的事件队列提交一个增加 idle 的请求GUI 线程的主循环在处理事件队列时,会把该 idle 函数放到 idle 管理器中,在分发 idle 时,该 idle 函数在 GUI 线程执行。
```c
/**
* @method idle_queue
* 用于非 GUI 线程增加一个 idle本函数向主循环的事件队列中发送一个增加 idle 的请求。
* @annotation ["static"]
* @param {idle_func_t} on_idle idle 回调函数。
* @param {void*} ctx idle 回调函数的上下文。
*
* @return {ret_t} 返回 RET_OK 表示成功,否则表示失败。
*/
ret_t idle_queue(idle_func_t on_idle, void* ctx);
```
2018-05-18 18:14:15 +08:00
> on\_idle 函数返回 RET\_REPEAT 时,将重复执行。
### 2. timer\_queue
timer\_queue 向主循环的事件队列提交一个增加 timer 的请求GUI 线程的主循环在处理事件队列时,会把该 timer 函数放到 timer 管理器中,在分发 timer 时,该 timer 函数在 GUI 线程执行。
```c
/**
* @method timer_queue
* 用于非 GUI 线程增加一个 timer本函数向主循环的事件队列中发送一个增加 timer 的请求。
* @annotation ["static"]
* @param {timer_func_t} on_timer
* timer 回调函数,回调函数返回 RET_REPEAT则下次继续执行否则自动移出。
* @param {void*} ctx timer 回调函数的上下文。
* @param {uint32_t} duration 时间。
*
* @return {ret_t} 返回 RET_OK 表示成功,否则表示失败。
*/
ret_t timer_queue(timer_func_t on_timer, void* ctx, uint32_t duration);
```
2018-05-18 18:14:15 +08:00
> on\_timer 函数返回 RET\_REPEAT 时,将重复执行。
2018-05-18 18:14:15 +08:00
### 3. tk\_run\_in\_ui\_thread
2018-05-18 18:14:15 +08:00
tk\_run\_in\_ui\_thread 让后台线程在 UI 线程执行指定的函数,它是对 idle\_queue 的包装,支持等待调用完成。
2018-05-18 18:14:15 +08:00
```c
/**
* @method tk_run_in_ui_thread
* 后台线程在 UI 线程执行指定的函数。
*
* @param {tk_callback_t} func 函数。
* @param {void*} ctx 回调函数的上下文。
* @param {bool_t} wait_until_done 是否等待完成。
*
* @return {ret_t} 返回 RET_OK 表示成功,否则表示失败。
*/
ret_t tk_run_in_ui_thread(tk_callback_t func, void* ctx, bool_t wait_until_done)
2018-05-18 18:14:15 +08:00
```
> 如果 wait\_until\_done 为 FALSEfunc 函数返回 RET\_REPEAT 时,将重复执行。
> 注意:以上是少数几个可以在非 GUI 线程安全调用的函数,请不要在非 GUI 线程调用其它 widget 相关的函数。
### 示例:
```c
void* test_thread1(void* args) {
int nr = 500000;
while ((nr-- > 0) && (!s_app_quit)) {
tk_run_in_ui_thread((tk_callback_t)update_progress_bar, args, TRUE);
sleep_ms(30);
}
return NULL;
}
void* test_thread2(void* args) {
int nr = 500000;
while ((nr-- > 0) && (!s_app_quit)) {
tk_run_in_ui_thread((tk_callback_t)update_progress_bar, args, FALSE);
sleep_ms(30);
}
return NULL;
2018-05-18 18:14:15 +08:00
}
static ret_t on_idle(const idle_info_t* idle) {
2018-06-16 11:40:13 +08:00
return update_progress_bar(WIDGET(idle->ctx));
2018-05-18 18:14:15 +08:00
}
void* test_thread3(void* args) {
int nr = 500000;
while ((nr-- > 0) && (!s_app_quit)) {
2018-05-18 18:14:15 +08:00
idle_queue(on_idle, args);
sleep_ms(30);
}
return NULL;
}
static ret_t on_timer(const timer_info_t* timer) {
return update_progress_bar(WIDGET(timer->ctx));
}
2018-05-18 18:14:15 +08:00
void* test_thread4(void* args) {
int nr = 500000;
while ((nr-- > 0) && (!s_app_quit)) {
timer_queue(on_timer, args, 30);
sleep_ms(30);
}
2018-05-18 18:14:15 +08:00
return NULL;
2018-05-18 18:14:15 +08:00
}
```
### 参考
> demos/demo\_thread\_app.c
2020-04-09 12:25:12 +08:00
### 注意事项
2018-05-18 18:14:15 +08:00
* 在 idle 函数执行的时候,窗口可能已经被关闭,控件已经处于无效状态。为了避免出现也指针的问题,在 idle 函数中,应该检查目标窗口和控件是否存在。