Signal_delete_event 不会在 set_current_page 的笔记本中更改页面

Signal_delete_event doesn't change page in notebook with set_current_page

我想在删除 window 时切换到笔记本中的某个页面,并在有效删除 window 之前做一些工作。 下面的代码为 get_current_page 提供了 1,但页面并未有效地更改为 1.

这个问题应该怎么解决?

Form::Form()
{
    add(box);

    notebook.set_size_request(800, 600);
    notebook.set_show_tabs(false);
    box.pack_start(notebook, Gtk::PACK_SHRINK);

    label_intro.set_text("Intro");
    box_intro.pack_start(label_intro);
    box_intro.show();

    label_exit.set_text("Preparing clean exit ... Please wait!");
    box_exit.pack_start(label_exit);
    box_exit.show();

    notebook.insert_page(box_intro, "Intro", 0);
    notebook.insert_page(box_exit, "Exit", 1);

    signal_delete_event().connect(sigc::mem_fun(*this, &Form::is_deleted));

    set_title("title");
    resize(800, 600);
    show_all();
}

bool Form::is_deleted(GdkEventAny *any_event)
{
    notebook.set_current_page(1);
    std::cout << "current_page " << notebook.get_current_page() << std::endl; // gives 1

    std::this_thread::sleep_for(2000ms);
    return Window::on_delete_event(any_event);
}

class Form : public Window
{
public:
    Form();
private:
    bool is_deleted(GdkEventAny *any_event);
private:
    // Form
    Box box;
    Notebook notebook;
    Box box_intro, box_exit;
    Label label_intro, label_exit;
};

抱歉回答晚了,你的问题比我想象的更让我工作!

使用 Glib::TimeoutSource class(可笑的是文档不足...),我能够绕过这个限制。

基本上,我的策略是单击一次 运行 delete-event 信号处理程序两次:

  1. 一次更新笔记本。在这种情况下,我们 return true 表示处理程序已经“完全处理”了信号,传播不应发生,因此不会关闭 window。此时,用户在 UI 中看到了变化,但还没有完成任何工作。在此过程中,我们还设置了一个 Glib::Timeout 以稍后调用 window 上的 close 方法,再次调用 delete-event 信号处理程序。
  2. 两次完成这项工作。这一次,我们做真正的工作(UI 已经更新)。工作完成后,我们传播处理程序并关闭 window.

这是代码*:

#include <chrono>
#include <iostream>
#include <thread>

#include <gtkmm.h>

using namespace std::chrono_literals;

class Form : public Gtk::Window
{

public:

    Form();

private:

    Gtk::Box      box;
    Gtk::Notebook notebook;
    Gtk::Box      box_intro;
    Gtk::Box      box_exit;
    Gtk::Label    label_intro;
    Gtk::Label    label_exit;

    // This flag indicates if a first call to the "delete-event" signal
    // has been done. On a second call to this event, this should be
    // set to "true" to alter the handler's behaviour.
    bool flag = false;
};

Form::Form()
{
    add(box); 
    notebook.set_size_request(800, 600);
    notebook.set_show_tabs(false);
    box.pack_start(notebook, Gtk::PACK_SHRINK);

    label_intro.set_text("Intro");
    box_intro.pack_start(label_intro);
    box_intro.show();

    label_exit.set_text("Preparing clean exit ... Please wait!");
    box_exit.pack_start(label_exit);
    box_exit.show();

    notebook.insert_page(box_intro, "Intro", 0);
    notebook.insert_page(box_exit, "Exit", 1);

    signal_delete_event().connect(
        [this](GdkEventAny *any_event)
        {
            if(!flag)
            {
                // First time in. We change the notebook page:
                notebook.set_current_page(1);

                // If we block right away and don't return from
                // this handler, the GUI will freeze. Hence, we set
                // a timer to "close" the window in 10ms. Not that
                // closing the window will call once more this handler...
                Glib::signal_timeout().connect(
                    [this]()
                    {
                        close();
                        return false; // Disconnect after on call...
                    },
                    10
                );

                // So we change the flag value, to alter its behavior on the
                // next pass.
                flag = true;

                return true; // Fully handled for now... leaving the handler.
                             // This will allow the main loop to be run and the
                             // window to uptate.
            }

            // On the second run, we do the work:
            std::this_thread::sleep_for(1900ms);

            // And we close the window (for real this time):
            return Window::on_delete_event(any_event);
        }
    );

    set_title("title");
    resize(800, 600);
    show_all();
}

int main(int argc, char *argv[])
{
    auto app = Gtk::Application::create(argc, argv, "org.gtkmm.examples.base");

    Form window;
    window.show_all();

    return app->run(window);
}

* 我冒昧地使用了 lambda 表达式,因为我认为它们更具可读性和封装性,我不确定你是否知道它们。无论如何,选择最好的。

我知道这是某种 hack,但在尝试了 很多 之后,我开始相信这是我们可以在不处理更多事情的情况下实现的最好结果涉及 multi-threading 策略(很遗憾,我不是这方面的专家)。

希望这至少能暂时解决您的问题。