You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Gtkmm 3.0优化百叶窗状态变化时线条闪烁的超时实现问询

最优实现方案建议

核心思路:仅在百叶窗状态变化时启动临时闪烁超时

不需要修改现有2分钟的数据获取超时,针对状态变化的百叶窗单独处理闪烁逻辑即可,具体步骤如下:

  • 跟踪百叶窗状态变化:维护一个缓存结构(比如哈希表),记录每个百叶窗的当前状态、闪烁状态及相关超时ID。当2分钟的超时回调获取到新数据时,对比缓存中的旧状态:
    • 若状态发生变化,标记该百叶窗进入闪烁状态,并启动单次1秒超时。
  • 闪烁超时回调逻辑:
    • 在1秒超时回调中,切换该百叶窗的闪烁显示状态(比如线条显/隐、颜色切换),调用Gtk::DrawingArea::queue_draw()触发重绘。
    • 如果闪烁次数未达预设次数(比如3次),再次启动下一个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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 09:02:59