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

如何在fltk-rs中实现fltk-grid组件内容更新并显示变化?

解决fltk-rs中fltk-grid组件更新部件不显示的问题

问题核心在于两点:

  • 每次点击按钮时创建的Frame是局部变量,函数执行完毕后就被销毁,FLTK无法渲染已释放的控件
  • 直接调用set_widget覆盖位置时,没有确保新控件被正确添加到窗口的控件树中并保留生命周期

修复方案:预先创建Frame并复用(推荐)

这种方式更高效,不需要每次创建新控件,只更新已有控件的标签即可。

修改grid.rs,在创建网格时就初始化Frame并持有引用:

use fltk::{frame, prelude::*};
use fltk_grid::Grid;
use std::{rc::Rc, cell::RefCell};

// 定义网格及需要更新的Frame的结构体
pub struct GridData {
    pub grid: Grid,
    pub message_frame: Rc<RefCell<frame::Frame>>,
}

pub fn create() -> GridData {
    let mut grid = Grid::default_fill();
    grid.show_grid(false);
    grid.set_layout(9, 9);

    // 初始化Frame并添加到网格
    let mut message_frame = frame::Frame::default().with_label("Number = 0.");
    grid.set_widget(&mut message_frame, 3, 4);

    GridData {
        grid,
        message_frame: Rc::new(RefCell::new(message_frame)),
    }
}

pub fn update(data: Rc<RefCell<u32>>, frame: Rc<RefCell<frame::Frame>>) {
    // 直接更新已有Frame的标签
    let label = format!("Number = {}.", data.borrow());
    frame.borrow_mut().set_label(&label);
    // 手动触发重绘确保更新显示
    frame.borrow_mut().redraw();
}

修改main.rs,使用新的GridData结构体持有网格和Frame:

use fltk::{app, prelude::*, window::Window, button};
use std::{cell::RefCell, rc::Rc};

mod grid;
fn main() {
    let number = Rc::new(RefCell::new(0));
    
    let app = app::App::default();
    let mut wind = Window::default()
        .with_size(900, 500)
        .center_screen()
        .with_label("Test app.");

    // 创建包含网格和Frame的GridData
    let grid_data = grid::create();
    let mut main_grid = grid_data.grid;
    let message_frame = grid_data.message_frame;

    // 添加按钮到网格
    let mut stats_button = button::Button::default().with_label("Update");
    main_grid.set_widget(&mut stats_button, 4, 4);

    main_grid.end();

    stats_button.set_callback(move |_| {
        *number.borrow_mut() += 1;
        // 调用update更新Frame标签
        grid::update(number.clone(), message_frame.clone());
    });

    wind.end();
    wind.show();

    app.run().unwrap();
}

方案说明

  • 预先创建的Frame被Rc<RefCell>持有,生命周期和窗口一致,不会被提前销毁
  • 每次点击只更新标签并触发重绘,避免重复创建控件,性能更优
  • 控件始终存在于网格的控件树中,FLTK能正确渲染

可选方案:动态创建控件并管理生命周期

如果确实需要动态创建控件,需要确保新控件被添加到父窗口中,并且保留其引用:

修改grid.rs的update函数:

// grid.rs
pub fn update(data: Rc<RefCell<u32>>, grid: &mut Grid) -> frame::Frame {
    let label = format!("Number = {}.", data.borrow());
    let mut message_frame = frame::Frame::default().with_label(&label);
    grid.set_widget(&mut message_frame, 3, 4);
    // 返回控件,让调用方持有生命周期
    message_frame
}

修改main.rs,用Rc<RefCell<Option<frame::Frame>>>保存动态创建的Frame:

// main.rs
fn main() {
    let number = Rc::new(RefCell::new(0));
    let message_frame = Rc::new(RefCell::new(None));
    
    let app = app::App::default();
    let mut wind = Window::default()
        .with_size(900, 500)
        .center_screen()
        .with_label("Test app.");

    let mut main_grid = grid::create();

    let mut stats_button = button::Button::default().with_label("Update");
    main_grid.set_widget(&mut stats_button, 4, 4);

    main_grid.end();

    stats_button.set_callback(move |_| {
        *number.borrow_mut() += 1;
        // 先移除旧的控件(如果存在)
        if let Some(mut old_frame) = message_frame.borrow_mut().take() {
            old_frame.hide();
            old_frame.remove();
        }
        // 创建新控件并保存引用
        let new_frame = grid::update(number.clone(), &mut main_grid);
        *message_frame.borrow_mut() = Some(new_frame);
        // 触发窗口重绘
        wind.redraw();
    });

    wind.end();
    wind.show();

    app.run().unwrap();
}

这种方式仅在确实需要动态增减控件时使用,性能不如预创建控件方案。

内容的提问来源于stack exchange,提问作者Valentino Amato

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 18:10:39