如何在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
相关产品推荐
相关产品推荐

