主循环
主循环的概念和相关功能介绍。
应用程序在运行的时候,为了能够不断的对用户的操作进行响应和反馈,通常的做法是将事件处理、状态更新和界面重绘等任务往复执行,而这一循环执行的过程即为主循环。
LCUI 的主循环所执行的任务包括处理定时器、处理事件队列、更新组件、渲染组件等,这些任务的调度代码都在 src/main.c 文件中的 LCUI_RunFrame() 函数中:
void LCUI_RunFrame(void)
{
LCUI_ProcessTimers();
LCUI_ProcessEvents();
LCUICursor_Update();
LCUIWidget_Update();
LCUIDisplay_Update();
LCUIDisplay_Render();
LCUIDisplay_Present();
}帧率控制
主循环的每次循环即为一帧,为了避免不必要的 CPU 资源占用,主循环的执行频率会受到帧率控制,预设的帧率限制是 120 帧每秒,也就是主循环每秒最多执行 120 遍,每帧至少占用约 8.33 毫秒的时间,如果一帧的耗时低于 8.33 毫秒则会利用剩下的时间进入休眠状态。
如果你想要自定义帧率限制,可以调用 LCUI_ApplySettings() 修改全局设置中的 frame_rate_cap 设置项:
#include <LCUI.h>
#include <LCUI/settings.h>
int main(void)
{
LCUI_SettingsRec settings;
Settings_Init(&settings);
settings.frame_rate_cap = 60;
LCUI_ApplySettings(&settings);
}多个主循环
试着考虑这种场景:在用户点击按钮后弹出一个确认框,等待用户点击确认后再执行操作。这种场景比较常见,我们会希望有个 ShowConfirmDialog() 函数能够完成这件事情:
按钮的点击事件处理器都是在主循环中执行的,如果 ShowConfirmDialog() 函数要等到用户点击弹框里的按钮后才退出的话,它在这段等待时间内会一直阻塞主循环的执行,导致整个界面无法响应用户操作,由于界面无法响应操作, ShowConfirmDialog() 函数也无法得知用户是否点击了确认按钮或取消按钮,这就成了一个死循环,那么如何解决此问题?有一种方法是在 ShowConfirmDialog() 函数中再创建一个主循环以响应后续的用户操作和界面更新,示例如下:
在这段代码中,先定义了DialogContextRec 类型的 ctx 变量用于记录按钮点击状态和主循环的指针,然后为确认按和取消按钮绑定点击事件处理器,之后调用 LCUIMainLop_New() 新建了一个主循环,再调用 LCUIMainLoop_Run() 执行这个新的主循环。在按钮被点击后,事件处理器会修改 ctx 中的按钮点击状态,然后调用 LCUIMainLoop_Quit() 退出指定的主循环。在LCUIMainLoop_Run() 函数退出后,销毁弹框并将用户的操作结果返回。
另一种方法是改用回调函数的响应操作结果:
我们不建议采用这种方法,因为它存在以下几个问题:
需要再定义一个函数接收操作结果,使得操作逻辑被分散。
如果这个函数需要额外的参数话,还要给
ShowConfirmDialog()再增加一个参数,增加了函数复杂度和代码量。由于 C 语言没有像 JavaScript 那样的闭包特性和对异步编程的 async/await 关键字支持,使得这种方法的实现代码和调用代码并不优雅。
不使用主循环
如果你的应用程序有自己的主循环,不希望为适应 LCUI 的主循环而做改动,那么可以在主循环中调用 LCUI_RunFrame() 函数:
最后更新于