how get destructor called for derived object from Gtk::Window - c++

I want to derive from Gtk::Window and want to create a stand alone window from that object. If the user closes that window, how can I achieve that the destructor of my derived object will be called.
I want to close it in the moment the window is destroyed by user. I tried to do it inside the "on_signal_delete" handler, but that results in segfault.
Currently my code did never call the destructor of the stand alone window!
#include <iostream>
#include <string>
#include <gtkmm.h>
class ExampleWindow : public Gtk::Window
{
protected:
//Child widgets:
Gtk::Box m_VBox;
Gtk::Label m_Label1;
std::string mytext;
public:
ExampleWindow(const std::string& text_):
m_VBox{ Gtk::ORIENTATION_VERTICAL }
,m_Label1{ text_ }
,mytext{ text_ }
{
set_title("Example");
set_border_width(10);
set_default_size(400, 200);
add(m_VBox);
m_VBox.pack_start( m_Label1 );
show_all_children();
}
virtual ~ExampleWindow()
{
// Not called for the stand alone win while closing it. How to achieve that?
std::cout << "Destructor called for " << mytext << std::endl;
}
bool on_delete_event( GdkEventAny* ) override
{
std::cout << "sig on delete called" << mytext << std::endl;
// free( this ); // that results in segfault
return true;
}
};
int main(int argc, char *argv[])
{
auto app = Gtk::Application::create(argc, argv, "some.base");
ExampleWindow window{ "First Window" };
// Create the same window as free window ( toplevel )
ExampleWindow* win2 = new ExampleWindow("Stand Alone Win");
win2->show(); // How can I desruct this window, if a user closes it?
//Shows the window and returns when it is closed.
return app->run(window);
}
EDIT: As comming up discussion from comments why it is not possible to not use new I provide this more complicated example to show that my real world application has to create the new windows from a signal handler inside gtk. So there is a need to create the objects on demand.
Full example which can create new windows on demand:
#include <iostream>
#include <string>
#include <gtkmm.h>
class ExampleWindow : public Gtk::Window
{
protected:
//Child widgets:
Gtk::Box m_VBox;
Gtk::Button m_button;
std::string mytext;
public:
ExampleWindow(const std::string& text_):
m_VBox{ Gtk::ORIENTATION_VERTICAL }
,m_button{ text_ }
,mytext{ text_ }
{
set_title("Example");
set_border_width(10);
set_default_size(400, 200);
add(m_VBox);
m_VBox.pack_start( m_button );
m_button.signal_clicked().connect(sigc::mem_fun(this,&ExampleWindow::on_clicked));
show_all_children();
}
void on_clicked()
{
ExampleWindow* win2 = new ExampleWindow("Stand Alone Win");
win2->show(); // How can I desruct this window, if a user closes it?
}
virtual ~ExampleWindow()
{
// Not called for the stand alone win while closing it. How to achieve that?
std::cout << "Destructor called for " << mytext << std::endl;
}
bool on_delete_event( GdkEventAny* ) override
{
std::cout << "sighandler on_delete called" << mytext << std::endl;
//delete this; // results in segfault
return false;
}
};
int main(int argc, char *argv[])
{
auto app = Gtk::Application::create(argc, argv, "some.base");
ExampleWindow window{ "Press to create new win" };
//Shows the window and returns when it is closed.
return app->run(window);
}
The question is still: Where can I hook into the signal handlers to free the dynamically created top level windows.

You dynamically allocate win2 but you never free the memory afterwards.
Call delete on win2 after Gtk::Application::run() returns:
delete win2;
Edit, after a discussion in the comments of this answer
Instead of dynamically allocating your pointer in ExampleWindow::on_clicked(), showing it and then forgetting about it, you should have some sort of a global registry, e.g. an array, of created windows that you can track and destroy when required. Coming up with a design on how to do this is not in scope of the original question so I won't suggest anything more concrete here. You can then even avoid having the dynamic allocation, as it was also suggested below.

Related

How to connect GTK+ signals (not gtkmm) to non-static class methods using libsigc++?

The goal is to connect GTK+ signals to non-static class methods using libsigc++ without gtkmm. I want to use the Glade user interface designer to design a non-trivial UI with many views, comparable to a setup wizard. The UI should be portable (Embedded Linux and Windows). So, I want to reduce the dependencies and use the C GTK+ only without the C++ language binding component gtkmm, but the UI should be written in C++. The MVC pattern should be applied to separate the responsibilities and for decoupling. As a result, my C++ views and other classes have to connect their signal handlers to the GTK+ C signals using g_signal_connect(). Later they have to use g_signal_handlers_disconnect_by_func() to disconnect the handlers. The following example demonstrates the problem:
File: GladeProgram.h
#ifndef _GLADEPROGRAMM_H
#define _GLADEPROGRAMM_H
#include "gtk/gtk.h"
class GladeProgram
{
public:
GladeProgram(int argc, char *argv[]);
virtual ~GladeProgram();
void Run();
void Exit();
};
#endif // !_GLADEPROGRAMM_H
File: GladeProgram.cpp
#include "GladeProgram.h"
#include "sigc++/sigc++.h"
GladeProgram::GladeProgram(int argc, char *argv[])
{
gtk_init(&argc, &argv);
}
GladeProgram::~GladeProgram()
{
}
// C-style callback method with object pointer
void onExit(GladeProgram* pProg)
{
pProg->Exit();
}
void GladeProgram::Run()
{
GtkBuilder *builder;
GtkWidget *window;
builder = gtk_builder_new_from_file("window_main.glade");
window = GTK_WIDGET(gtk_builder_get_object(builder, "window_main"));
// C-style signal handler with object pointer
g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(onExit), this);
// PROBLEM: Howto connect non-static class method GladeProgram::Exit() with libsigc++ ???
// g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK( ??? ), NULL);
g_object_unref(builder);
gtk_widget_show(window);
gtk_main();
}
void GladeProgram::Exit()
{
gtk_main_quit();
}
File: Main.cpp
#include <iostream>
#include "GladeProgram.h"
using namespace std;
int main(int argc, char *argv[])
{
std::cout << "**********************************************************************" << endl;
std::cout << "* GTK+ Test UI *" << endl;
std::cout << "**********************************************************************" << endl;
GladeProgram prog(argc, argv);
prog.Run();
// wait until the Enter key is pressed
cout << endl << "Press [Enter] to exit." << endl;
cin.get();
return 0;
}
The test program (console program) currently runs on Windows 10 and is compiled with Visual Studio 2017.
Any help is appreciated.

gtkmm get size of widget

I simply want to know which size a widget has. I need this info to set a ScrolledWindow to a maximum size if the size of the widget is bigger than the screen.
But all functions I know give a constant value of 1.
#include <iostream>
#include <gtkmm.h>
#include <gtkmm/window.h>
class ExampleWindow: public Gtk::Window
{
Gtk::Button button;
public:
ExampleWindow(): button("Hallo")
{
add(button);
GetSize();
}
void GetSize()
{
std::cout << button.get_width() << " " << button.get_height() << std::endl;
std::cout << button.get_allocated_width() << " " << button.get_allocated_height() << std::endl;
}
};
int main(int argc, char* argv[])
{
Gtk::Main kit(argc, argv);
ExampleWindow window;
window.GetSize();
window.show_all_children();
window.GetSize();
Gtk::Main::run(window);
return 0;
}
This looks a lot like this answer.
Basically it says that before the get_height() and get_width() methods return meaningful values, the widget must be realized. Since you are calling these (through your GetSize() wrapper) inside the window constructor, it (the button inside the window) might not yet be realized, hence the wrong values.
BONUS
According to this ticket:
Realize means to create the GDK resources for a widget. i.e. to
instantiate the widget on the display.
Also, to clarify the meaning of the word realize, see this. The author seems to have done some interesting research on the subject to clarify the documentation.

Display the value of an entry

i am using the library Gtkmm with c++ but i have a problem to display the value of an entry. This is my code :
#include <gtkmm/box.h>
#include <gtkmm/button.h>
#include <gtkmm/main.h>
#include <gtkmm/window.h>
#include <gtkmm/entry.h>
#include <iostream>
int main(int argc, char* argv[]) {
Gtk::Main app(argc, argv);
Gtk::Window fenetre;
Gtk::VBox *boiteV = Gtk::manage(new Gtk::VBox(false, 10));
Gtk::Entry *param = Gtk::manage(new Gtk::Entry());
boiteV->pack_start(*param);
Gtk::Button *bouton = Gtk::manage(new Gtk::Button("Tester !"));
boiteV->pack_start(*bouton);
fenetre.add(*boiteV);
std::string a = param->get_text();
bouton->signal_clicked().connect([&a]() {std::cout << a << std::endl;});
fenetre.show_all();
Gtk::Main::run(fenetre);
return EXIT_SUCCESS;
}
My problem is when i click on the button i have nothing whereas i wrote a value in the entry. Thank you a lot for your help !
The problem is that you take the string a after creation of the button and capture that string (which is empty) in the lambda function. When you press the button, the text is not queried again, but the value of the string a, which never changed, is printed.
You can instead capture the pointer to the button itself (by value!) and call get_text() every time like this:
bouton->signal_clicked().connect(
[param]() {
std::cout << param->get_text() << std::endl;
}
);

gtkmm: How to detect arrow key is pressed

What event can i connect to in order to detect arrow keys being pressed when a user is in a window.
So far i have tried to connect via on_key_press_event and i checked keyval, hardware_keycode, and state.
#include <gtkmm.h>
#include <iostream>
class MyWindow : public Gtk::Window
{
public:
MyWindow();
bool onKeyPress(GdkEventKey*);
};
MyWindow::MyWindow()
{
set_title("arrow_button_test");
this->signal_key_press_event().connect( sigc::mem_fun( *this, &MyWindow::onKeyPress ) );
}
bool MyWindow::onKeyPress(GdkEventKey* event)
{
std::cout << event->keyval << ' ' << event->hardware_keycode << ' ' << event->state << std::endl;
return false;
}
int main(int argc, char** argv)
{
Glib::RefPtr<Gtk::Application> app = Gtk::Application::create(argc, argv, "com.almost-university.gtkmm.arrow_button_press");
MyWindow window;
app->run(window);
return 0;
}
This code generates no output on arrow keys, meaning that event isn't even fired off.
If you change
this->signal_key_press_event().connect(
sigc::mem_fun(*this, &MyWindow::onKeyPress));
to
this->signal_key_press_event().connect(
sigc::mem_fun(*this, &MyWindow::onKeyPress), false);
your signal handler should receive the events. That false argument is for the after flag. It is true by default, meaning that other signal handlers may intercept the signal before MyWindow::onKeyPress, since it is the last one.

How can you update the gtkmm gui screen from your c++ code after it is created

Can someone help to clear up the confusion of how to update a gui window without user input.
In other words, I would like to be able to output text to either or both the console our the gui window.
At present I can call the gui window (Window with a label for example) and output the initial text. However, the process doesn't return to my c++ code until the window closes. I'm trying to figure out how to (or where to have my code) for updating the gui screen before the gui window exits.
This is an example:
#include <gtkmm.h>
#include <iostream>
using namespace std;
int main(int argc, char* argv[])
{
Gtk::Main kit(argc, argv);
Gtk::Window window;
Gtk::TextView textview;
Gtk::Label label;
string mylabeltext = "This is the first line of text in my gui window.\n";
window.set_default_size(600, 360);
window.set_title("Gtkmm Programming - C++");
window.set_position(Gtk::WIN_POS_CENTER);
label.show();
window.add(label);
label.set_text(mylabeltext);
mylabeltext += "About to run some routines...\n";
label.set_text(mylabeltext);
cout << "An initial line has been set to the gui window." << endl;
// The Gui Window is displayed
Gtk::Main::run(window);
// Now my main program has performed some functions and wants to update
// the console and the gui window.
cout << "Continuing after various functions and processing..." << endl;
mylabeltext = "Showing the results of the functions and processing.";
label.set_text(mylabeltext);
return 0;
}
The last line of text is never printed to the console until the gui is exited. The last line of the mylabeltext is never printed to the label window.
What I'm trying to describe is how to keep the gtkmm window active while I run other routines in my c++ code and update the output to both the console and the gui window without closing the gui window to continue the c++ routines.
All the examples that I can find uses a button in the code. I have tested and experimented enough that I can update the gui screen after a button is pressed. However, I don't want to have to rely on the user for screen updates. I hope to be able to run disc scans and other functions and periodically update the screen so that the user can see the progress and know that the program is still working and not dead.
Some of the resources that I have studied in my attempts at understanding this include:
https://developer.gnome.org/
https://developer.gnome.org/gtkmm-tutorial/3.2/gtkmm-tutorial.html
http://en.wikipedia.org/wiki/Gtkmm
Like tp1 said in their comment on your question, a timer is going to be the easiest way to do this.
To set a 1.5 second timeout that will call another function, do this (gtkmm 3):
#include <gtkmm.h>
#include <iostream>
using namespace std;
class MyApp : public Gtk::Window{
public:
Gtk::Label label;
bool on_timeout(); //return true to keep the timeout and false to end it
MyApp();
virtual ~MyApp();
};
MyApp::MyApp(){
string mylabeltext = "This is the first line of text in my gui window.\n";
set_default_size(600, 360);
set_title("Gtkmm Programming - C++");
set_position(Gtk::WIN_POS_CENTER);
add(label);
label.set_text(mylabeltext);
mylabeltext += "About to run some routines...\n";
label.set_text(mylabeltext);
cout << "An initial line has been set to the gui window." << endl;
//create slot for timeout signal
int timeout_value = 1500; //in ms (1.5 sec)
sigc::slot<bool>my_slot = sigc::mem_fun(*this, &MyApp::on_timeout);
//connect slot to signal
Glib::signal_timeout().connect(my_slot, timeout_value);
show_all_children();
}
MyApp::~MyApp(){
}
bool MyApp::on_timeout(){
cout << "Continuing after various functions and processing..." << endl;
string temp = label.get_text();
temp += "Showing the results of the functions and processing.\n";
label.set_text(temp);
return true;
}
int main(int argc, char* argv[])
{
Glib::RefPtr<Gtk::Application> app = Gtk::Application::create(argc, argv, "com.kaze.test");
MyApp myapp;
// The Gui Window is displayed
return app->run(myapp);
}
More info here: https://developer.gnome.org/gtkmm-tutorial/3.3/sec-timeouts.html.en
This is crude, but this is functional for what I was trying to do:
#include <gtkmm.h>
#include <iostream>
using namespace std;
class myLabel: public Gtk::Window
{
public:
myLabel();
virtual ~myLabel();
protected:
Gtk::Label m_label;
string labeltext;
string newtext;
void myprocess1();
};
myLabel::myLabel() :
m_label()
{
void myprocess1();
set_title("Gtkmm Programming - C++");
add(m_label);
m_label.show();
Glib::Thread::create(sigc::mem_fun(*this, &myLabel::myprocess1), true);
}
myLabel::~myLabel()
{
}
void myLabel::myprocess1()
{
labeltext = "About to preform a number of processes.\n";
labeltext += "Each process may take up to three hours.\n";
labeltext += "Please carry your daily chores and wait.\n";
cout << labeltext;
cout.flush();
m_label.set_text(labeltext);
sleep(10); // Back from a three hour function
newtext = "Back from a three hour function\n";
labeltext += newtext;
m_label.set_text(labeltext);
cout << newtext;
cout.flush();
sleep(10); // Back from a three hour function
newtext = "Back from another three hour function\n";
labeltext += newtext;
m_label.set_text(labeltext);
cout << newtext;
cout.flush();
newtext = "Exiting in 1 minute...\n";
labeltext += newtext;
m_label.set_text(labeltext);
cout << newtext;
cout.flush();
sleep(60);
exit(0);
}
int main(int argc, char* argv[])
{
if (Glib::thread_supported())
Glib::thread_init();
else
{
cerr << "Threads aren't supported!" << endl;
exit(1);
}
Gtk::Main kit(argc, argv);
myLabel mylabel;
Gtk::Main::run(mylabel);
return 0;
}
Hope the example can help anyone else that wants to output to the gtkmm gui with updates, similar to updating info to the console.