rust gtk-rs从按钮按下获取用户输入

tjrkku2a  于 2023-01-05  发布在  其他
关注(0)|答案(1)|浏览(198)

我有一个gtk-rs应用程序,当用户点击提交按钮时,Gtk::Entry用于获取用户输入。所有内容都会编译并运行,但我无法在处理按钮按下的方法之外获取用户输入。
我可以检查是否从按钮单击处理程序内部正确地收集了输入,但是从方法外部获取字符串目前不起作用。
我发现了类似的问题,花了很多时间在谷歌上搜索这个问题,但到目前为止,我还没有找到这个问题的解决方案。事实上,我甚至没有发现任何人问同样的问题,这让我觉得要么我问错了问题,要么我试图以一种非常糟糕的方式来做这件事。
代码就在这里,我想在button.connect_clicked方法外得到user_input变量。
代码:

use gtk::prelude::*;
use gtk::{Button, Orientation};
use std::cell::RefCell;
use std::rc::Rc;

pub fn login_view() -> (gtk::Box, String) {
    let button = Button::builder()
        .label("Submit")
        .margin_top(6)
        .margin_bottom(12)
        .margin_start(12)
        .margin_end(12)
        .build();

    let input = gtk::Entry::builder()
        .placeholder_text("input")
        .margin_top(12)
        .margin_bottom(6)
        .margin_start(12)
        .margin_end(12)
        .build();

    let login_box = gtk::Box::builder()
        .orientation(Orientation::Vertical)
        .build();
    login_box.append(&input);
    login_box.append(&button);

    let mut user_input = Rc::new(RefCell::new(String::new()));
    let user_clone = user_input.clone();

    button.connect_clicked(move |_| {
        user_input.replace((format!("{}", input.text())));
        println!("user input = {}", user_input.borrow().to_string());
        input.set_text("");
    });

    println!("user_clone: {}", user_clone.borrow().to_string());
    return (login_box, user_clone.borrow().to_string());
}

输出:

user_clone: 
user input = dsfdsfds // this line repeats as many times as you hit the button.

这可能是一个潜在的异步问题,即在收集用户输入之前调用println!("user_clone: {}", user_clone.borrow().to_string());,然后再也不运行,但如果是这种情况,我也不知道如何处理这种情况,因为connect_clicked方法并没有真正完成,它只是在每次单击按钮时运行。
最终的目标是得到输入值并将其存储在一个结构体中,所以无论如何,我可以将这个输入值存储到一个已经声明的结构体中,这将是理想的。

xwbd5t1u

xwbd5t1u1#

我们已经开始走上正确的道路,我们使用了Rc<RefCell<String>>来共享所有权,并保持可变性,所以不是只返回函数末尾的内容,而是可以返回整个user_clone。但是你我很快就会意识到,图形应用程序通常是多线程的,这是有原因的,因此Rc<...>必须是SendSync或两者都有。所以我建议换成Arc<Mutex<String>>(或者用RwLock替换Mutex

use gtk::prelude::*;
use gtk::{Application, ApplicationWindow, Button, Orientation};
use std::sync::{Arc, Mutex};

pub fn login_view() -> (gtk::Box, Arc<Mutex<String>>) {
    // ...

    let user_input = Arc::new(Mutex::new(String::new()));

    button.connect_clicked({
        let user_input = Arc::clone(&user_input);
        move |_| {
            let mut user_input = user_input.lock().unwrap();
            *user_input = input.to_string();
            println!("user input = {}", user_input);
            input.set_text("");
        }
    });

    println!("user_clone: {}", user_input.lock().unwrap().to_string());
    return (login_box, user_input);
}

fn run_ui(app: &Application) {
    let (view, string) = login_view();
    let window = ApplicationWindow::builder()
        .application(app)
        .title("Hello Gtk")
        .child(&view)
        .build();

    // example use from another thread
    std::thread::spawn(move || loop {
        std::thread::sleep_ms(1000);
        println!("user_input: {}", string.lock().unwrap());
    });
    window.present();
}

然后你可以把返回的Arc<Mutex<String>>放到你想要原始String的结构体中,无论何时你从它读取,你都会得到最新的版本。

相关问题