繁体   English   中英

从 ListView 中删除 EditableLabel 时 gtk4/rust 断言失败

[英]gtk4/rust failed assertion when removing EditableLabel from ListView

在下面的 gtk4 代码中,我试图通过删除相应的StringObject从显示中删除EditableLabel 这应该在connect_editing_notify回调指定的编辑完成后发生。

如果我使用返回键运行程序并退出编辑模式,那么它会按预期工作:标签消失。 但是,如果我通过选择不同的标签退出编辑模式,那么我会得到一个重复的控制台打印,说明断言失败:

(viewdb:13773): Gtk-CRITICAL **: 17:35:26.754: gtk_widget_get_parent: assertion 'GTK_IS_WIDGET (widget)' failed

(viewdb:13773): Gtk-CRITICAL **: 17:35:26.754: gtk_widget_get_parent: assertion 'GTK_IS_WIDGET (widget)' failed

(viewdb:13773): Gtk-CRITICAL **: 17:35:26.754: gtk_widget_get_parent: assertion 'GTK_IS_WIDGET (widget)' failed

编辑后如何干净地删除 EditableLabel ?

use gtk::glib::clone;
use gtk::prelude::*;

use gtk::{
    Application, ApplicationWindow, EditableLabel, ListView, SignalListItemFactory,
    SingleSelection, StringList, StringObject, Widget,
};

fn build_ui(app: &Application) {
    let model: StringList = vec!["One", "Two", "Three", "Four"].into_iter().collect();

    let selection_model = SingleSelection::new(Some(&model));

    let factory = SignalListItemFactory::new();
    factory.connect_setup(move |_, listitem| {
        let label = EditableLabel::builder().build();

        listitem.set_child(Some(&label));

        listitem
            .property_expression("item")
            .chain_property::<StringObject>("string")
            .bind(&label, "text", Widget::NONE);

        label.connect_editing_notify(
            clone!( @strong model, @strong listitem => move |lbl: &EditableLabel| {
                if !lbl.is_editing() {
                    let position = listitem.position();
                    model.remove(position); // remove model entry cooresponding to edit.
                }
            }),
        );
    });

    let view = ListView::new(Some(&selection_model), Some(&factory));

    let window = ApplicationWindow::builder()
        .application(app)
        .child(&view)
        .build();

    window.present();
}

fn main() {
    let app = Application::builder().build();
    app.connect_activate(build_ui);
    app.run();
}

在项目仍在处理某些事件时从其父项目中移除项目有时会导致问题。

简单的解决方法是在延迟函数中进行删除。 在 C 语言中,可以使用g_idle_add()来完成,但正确使用会很麻烦。 但在 Rust 中,这非常简单:

gtk::glib::source::idle_add_local_once(
    clone!(@strong model => 
        move || model.remove(position)
    )
);

但请注意,由于idle函数会在未来某个未指定的时间运行,因此当回调运行时position的值(列表中的普通索引)可能会引用不同的项目,尽管可能性很小。

我没有测试它,但我认为将listitem本身保留在回调中更明智:

gtk::glib::source::idle_add_local_once(
    clone!(@strong model, @weak listitem => 
        move || {
            let position = listitem.position();
            if position != INVALID_LIST_POSITION {
                model.remove(position)
            }
        }
    )
);

弱克隆将确保仅在项目仍然存在时才调用它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM