fltk-rs中如何让闭包内的files变量在外部可访问?
问题原因
你在按钮回调里犯了一个关键错误:选择文件后,你没有修改共享的RefCell内部的Vec,而是重新创建了一个新的Rc<RefCell<Vec<PathBuf>>>并赋值给闭包内的files变量。这导致闭包内的files指向新实例,而MyApp结构体里的files仍指向最初的空Vec实例,两者不再共享数据。
修正方案
修改回调内的代码,通过borrow_mut()获取RefCell的可变引用,直接修改内部的Vec内容,而非替换整个Rc实例:
btn_files_select.set_callback({ let files = files.clone(); // 克隆共享的Rc move |_| { let mut dialog = dialog::NativeFileChooser::new(dialog::NativeFileChooserType::BrowseMultiFile); if dialog.show() == dialog::NativeFileChooserResult::Ok { // 检查用户是否确认选择 let selected_files = dialog.filenames(); *files.borrow_mut() = selected_files; // 修改共享的RefCell内部Vec } } });
完整修正后的代码
use fltk::{prelude::*, *}; use fltk_theme::{ColorTheme, WidgetTheme, ThemeType, color_themes}; use std::path::PathBuf; use std::cell::RefCell; use std::rc::Rc; #[derive(Copy, Clone)] pub enum Message { Send, Test, } #[derive(Clone)] pub struct MyApp { app: app::App, main_window: window::Window, receiver: app::Receiver<Message>, input_host: input::Input, input_username: input::Input, input_password: input::SecretInput, files: Rc<RefCell<Vec<PathBuf>>>, } impl MyApp { pub fn new() -> Self { let app = app::App::default().with_scheme(app::Scheme::Base); let (s, receiver) = app::channel(); let theme = ColorTheme::new(color_themes::BLACK_THEME); let widget_theme = WidgetTheme::new(ThemeType::AquaClassic); theme.apply(); widget_theme.apply(); let mut main_window = window::Window::default().with_size(800, 500).with_label("SSH conectivity").center_screen(); main_window.make_resizable(true); let flex = group::Flex::default().with_size(300, 200).with_type(group::FlexType::Column).with_pos(100, 100); let _label_host = frame::Frame::default().with_size(40, 0).with_label("Hostname"); let input_host = input::Input::default(); let _label_username = frame::Frame::default().with_size(40, 0).with_label("User"); let input_username = input::Input::default(); let _label_password = frame::Frame::default().with_size(40, 0).with_label("Password"); let input_password = input::SecretInput::default(); let mut btn_files_select = button::Button::default().with_size(100, 30).with_label("Select files"); flex.end(); let mut button_send = button::Button::default().with_size(50, 40).with_pos(150, 350).with_label("Send"); button_send.emit(s, Message::Send); let mut button_test = button::Button::default().with_size(50, 40).with_pos(250, 350).with_label("Test"); button_test.emit(s, Message::Test); main_window.end(); main_window.show(); let files = Rc::new(RefCell::new(Vec::new())); // 简化初始化写法 btn_files_select.set_callback({ let files = files.clone(); move |_| { let mut dialog = dialog::NativeFileChooser::new(dialog::NativeFileChooserType::BrowseMultiFile); if dialog.show() == dialog::NativeFileChooserResult::Ok { *files.borrow_mut() = dialog.filenames(); } } }); Self { app, main_window, receiver, input_host, input_username, input_password, files } } pub fn run(mut self) { while self.app.wait() { if let Some(msg) = self.receiver.recv() { match msg { Message::Send => { println!("{:?}", self.files.borrow()); // 借用RefCell查看内容 }, Message::Test => { println!("Test"); }, } } } } }
关键说明
- 用
Rc::new(RefCell::new(Vec::new()))简化初始化,逻辑和原写法一致但更清晰。 - 回调内通过
files.borrow_mut()获取可变引用,直接替换内部Vec,所有共享该Rc的地方都会同步看到更新后的内容。 - 增加对话框结果检查,避免用户取消选择时覆盖已有文件列表。
内容的提问来源于stack exchange,提问作者darkphoenix
相关产品推荐
相关产品推荐

