Gtkmm 3.0优化百叶窗状态变化时线条闪烁的超时实现问询
最优实现方案建议
核心思路:仅在百叶窗状态变化时启动临时闪烁超时
不需要修改现有2分钟的数据获取超时,针对状态变化的百叶窗单独处理闪烁逻辑即可,具体步骤如下:
- 跟踪百叶窗状态变化:维护一个缓存结构(比如哈希表),记录每个百叶窗的当前状态、闪烁状态及相关超时ID。当2分钟的超时回调获取到新数据时,对比缓存中的旧状态:
- 若状态发生变化,标记该百叶窗进入闪烁状态,并启动单次1秒超时。
- 闪烁超时回调逻辑:
- 在1秒超时回调中,切换该百叶窗的闪烁显示状态(比如线条显/隐、颜色切换),调用
Gtk::DrawingArea::queue_draw()触发重绘。 - 如果闪烁次数未达预设次数(比如3次),再次启动下一个1秒超时;若已完成闪烁,清除该百叶窗的闪烁标记并终止超时。
- 在1秒超时回调中,切换该百叶窗的闪烁显示状态(比如线条显/隐、颜色切换),调用
- 重绘时区分处理:在
draw回调中遍历所有百叶窗:- 非闪烁状态的百叶窗,按实际状态正常绘制线条。
- 闪烁状态的百叶窗,根据当前闪烁阶段决定是否绘制线条。
额外优化点
- 限制闪烁周期:设置固定闪烁次数(比如3次共3秒),避免无意义的资源消耗。
- 超时冲突处理:状态变化时若已有未完成的超时,先取消旧超时再启动新的,避免逻辑混乱。
- 轻量状态存储:用简单结构体存储每个百叶窗的
实际状态、是否闪烁、剩余闪烁次数、超时ID,无需复杂全局状态。
伪代码示例
// 存储百叶窗状态的结构体 struct BlindState { bool actual_state; // 百叶窗实际开关状态 bool blink_visible; // 当前闪烁阶段是否显示线条 int blink_remaining; // 剩余闪烁次数 guint timeout_id; // 当前超时ID,用于取消 }; std::unordered_map<int, BlindState> blind_states; Gtk::DrawingArea* drawing_area; // 全局或类成员引用 // 2分钟数据获取超时回调 bool fetch_data_timeout() { auto new_blind_data = fetch_from_internet(); for (auto& [blind_id, new_state] : new_blind_data) { auto& state = blind_states[blind_id]; if (state.actual_state != new_state) { state.actual_state = new_state; // 初始化闪烁参数 state.blink_remaining = 3; state.blink_visible = true; // 取消已有超时(如果存在) if (state.timeout_id != 0) { g_source_remove(state.timeout_id); } // 启动新的1秒闪烁超时 state.timeout_id = g_timeout_add_seconds(1, blink_timeout, (gpointer)blind_id); } } drawing_area->queue_draw(); return true; // 保持2分钟超时持续运行 } // 闪烁超时回调 gboolean blink_timeout(gpointer data) { int blind_id = GPOINTER_TO_INT(data); auto& state = blind_states[blind_id]; // 切换闪烁显示状态 state.blink_visible = !state.blink_visible; state.blink_remaining--; drawing_area->queue_draw(); if (state.blink_remaining <= 0) { // 闪烁结束,重置状态 state.timeout_id = 0; return false; // 终止该超时 } return true; // 继续下一次1秒超时 } // DrawingArea的draw回调 bool on_draw(const Cairo::RefPtr<Cairo::Context>& cr) { // 绘制房屋布局pixbuf cr->set_source_pixbuf(pixbuf, 0, 0); cr->paint(); // 绘制房间温度... // 绘制百叶窗线条 for (auto& [blind_id, state] : blind_states) { if (state.blink_remaining > 0) { // 闪烁状态:根据当前阶段决定是否绘制 if (state.blink_visible) { draw_blind_line(cr, blind_id, state.actual_state); } } else { // 正常状态,绘制对应线条 draw_blind_line(cr, blind_id, state.actual_state); } } return true; }
这种方式既保留了原有2分钟的数据获取逻辑,又只在需要时启动闪烁超时,完全避免了每秒全局超时的资源浪费,逻辑更轻量化且清晰。
内容的提问来源于stack exchange,提问作者bejo
相关产品推荐
相关产品推荐

