I'd like to change to a certain page in a notebook when deleting the window and do some work before effectively deleting the window. The code below gives 1 for get_current_page, but the page isn't effectively changed to 1.
What should be the solution to this problem?
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;
};
Sorry for the late answer, your question made my work more than I thought!
Working with the Glib::TimeoutSource
class (which is ridiculously under documented...), I was able to hack my way around this limitation.
Basically, my strategy was, on a single click, to run the delete-event
signal handler two times:
true
to indicate the handler has "fully handled" the signal, and propagation should not happen, hence not closing the window. At this point, the user sees the change in the UI, but no work has been done. In this pass, we also set a Glib::Timeout
to later call the close
method on the window, calling once again the delete-event
signal handler.Here is this code*:
#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);
}
* I took the liberty to use lambda expressions, as I think they are more readable and encapsulated, and I wasn't sure if you knew about them. In any case, take what feels best.
I understand this is some sort of a hack, but after having tried a lot of things, I have come to believe this is the best we can achieve without dealing with more involved multi-threading strategies (which I am no expert of, sadly).
Hopes this, at least temporarily, solves your issue.