首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >第二个gtk_main_quit()不工作

第二个gtk_main_quit()不工作
EN

Stack Overflow用户
提问于 2017-05-29 03:53:01
回答 2查看 1K关注 0票数 0

在应用程序中,我嵌套gtk事件循环,以便能够在回调中返回值。但是,对于已经调用gtk_main_quit()的回调,我有一些问题,因为对该函数的多次调用似乎没有退出那么多事件循环嵌套。

下面是我的问题的一个例子:

代码语言:javascript
运行
复制
extern crate gtk;

use std::sync::Arc;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering;
use std::thread;

use gtk::{Button, ButtonExt, ContainerExt, Continue, Inhibit, WidgetExt, Window, WindowType};

fn main() {
    gtk::init().unwrap();
    let window = Window::new(WindowType::Toplevel);

    let quit = Arc::new(AtomicBool::new(false));

    window.connect_delete_event(|_, _| {
        gtk::main_quit();
        Inhibit(false)
    });

    let button = Button::new_with_label("Click");
    let quit2 = quit.clone();
    button.connect_clicked(move |_| {
        let quit = quit2.clone();
        thread::spawn(move || {
            quit.store(true, Ordering::Relaxed);
        });
        println!("Run");
        gtk::main();
    });
    window.add(&button);
    window.show_all();

    gtk::idle_add(move || {
        if quit.load(Ordering::Relaxed) {
            println!("Quit");
            gtk::main_quit();
            gtk::main_quit();
            quit.store(false, Ordering::Relaxed);
        }
        Continue(true)
    });

    gtk::main();
}

正如您在gtk::idle_add调用中看到的那样,我调用了gtk::main_quit()两次,在按下按钮时应该退出应用程序,因为gtk::main()也被调用了两次(一次在main函数的末尾,另一次在按钮中单击回调)。但是,当我单击按钮时,应用程序不会退出。

gtk的文件似乎表明,这是预期的行为:

使主循环最内部的调用在恢复控制时返回

(重点是我的)

因此,我认为这不会退出应用程序,因为调用gtk::main_quit()两次不会允许gtk主循环“重获控制权”。

我的问题是,在对gtk::main_quit()的两个调用之间,我应该做什么来停止事件循环的两个嵌套?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-05-29 11:47:23

我通过手动创建一个glib MainLoop并使用它来解决我的问题,而不是嵌套调用gtk事件循环。

票数 0
EN

Stack Overflow用户

发布于 2017-05-31 18:53:13

简单回答:解决方案是将第二个gtk::main_quit替换为:

代码语言:javascript
运行
复制
gtk::idle_add(|| {
    gtk::main_quit();
    Continue(false)
});

和前面一样,第一个gtk::main_quit()将安排内部主循环退出。此外,空闲处理程序将被外部主循环所捕获,从而导致它也立即终止。

这可以用一个伪递归函数进行推广,该函数在必要时多次重复该过程:

代码语言:javascript
运行
复制
fn deep_main_quit(n: usize) {
    if n == 0 {
        return;
    }
    gtk::main_quit();
    gtk::idle_add(move || {
        deep_main_quit(n - 1);
        Continue(false)
    });
}

请注意,使用idle_add连续检查标志将导致繁忙的循环,您几乎肯定希望避免这种情况。(在我的机器上,运行您的程序需要一个完整的CPU核心。)通常,首选的方法是等待条件变量。但是,如果您只需要告诉GUI线程做一些事情,如代码所示,您只需从另一个线程调用glib::idle_add即可。提供的回调将在GUI线程中排队并执行。

通过此更改,一个线程在GUI线程中释放两个级别的gtk_main,如下所示:

代码语言:javascript
运行
复制
fn main() {
    gtk::init().unwrap();
    let window = Window::new(WindowType::Toplevel);

    window.connect_delete_event(|_, _| {
        gtk::main_quit();
        Inhibit(false)
    });

    let button = Button::new_with_label("Click");
    button.connect_clicked(|_| {
        thread::spawn(|| {
            glib::idle_add(|| {
                println!("Quit");
                deep_main_quit(2);
                Continue(false)
            });
        });
        println!("Run");
        gtk::main();
    });
    window.add(&button);
    window.show_all();

    gtk::main();
}
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/44234358

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档