I'm a newbie to Gtk3 but I can't find how to do what I want anywhere. I'm trying to get a tree view representing article citations.
Desired outcome:
columns are resizable
no horizontal scrollbar
columns take only as much space as needed, they don't expand the window if content is too long
in case a cell's content is too long, either break the text over several lines (best) or trim it and add "..." (ok), just trim it (I could settle for that)
As an example of what I want, here's Zotero trimming columns with "..."
This is my widget hierarchy:
What I tried (using Glade + C):
Default settings: a horizontal scrollbar appears
Set ScrolledWindow horizontal scroll policy to "Never", auto sizing to column: window expands to fit content, e.g.
Set ScrolledWindow horizontal scroll policy to "Never", fixed sizing columns, with maximum width: contents is trimmed (not "...", no text reflow), but I can only resize columns to the arbiratry size I've given them.
Set ScrolledWindow horizontal scroll policy to "External", auto sizing columns, columns set to resizable: columns are not resizable, contents is not trimmed.
Here's variation 4 with source + XML file generated by Glade:
#include <gtk/gtk.h>
void on_window_main_destroy();
enum {
AUTHORS_COLUMN = 0,
TITLE_COLUMN,
N_COLUMNS
};
static void init_reference_list(GtkBuilder* builder)
{
GtkCellRenderer* renderer;
GtkWidget* tree_widget;
tree_widget = GTK_WIDGET(gtk_builder_get_object(builder, "tree_view"));
// -- Add attributes to Glade-generated columns
GtkTreeViewColumn* column;
renderer = gtk_cell_renderer_text_new();
column = GTK_TREE_VIEW_COLUMN(gtk_builder_get_object(builder, "title"));
gtk_tree_view_column_pack_start(column, renderer, FALSE);
gtk_tree_view_column_add_attribute(column, renderer, "text", TITLE_COLUMN );
column = GTK_TREE_VIEW_COLUMN(gtk_builder_get_object(builder, "authors"));
gtk_tree_view_column_pack_start(column, renderer, FALSE);
gtk_tree_view_column_add_attribute(column, renderer, "text", AUTHORS_COLUMN );
// -- Set up store and connect it to view
GtkListStore* store;
store = gtk_list_store_new(N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING );
gtk_tree_view_set_model(GTK_TREE_VIEW(tree_widget), GTK_TREE_MODEL(store));
// -- Placing fake data in store
char title[] = "A long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long title";
char authors[] = "Me You Us Them All of us";
GtkTreeIter iter;
int i;
for (int i = 0; i < 500; ++i)
{
gtk_list_store_append(store, &iter);
gtk_list_store_set(store, &iter, AUTHORS_COLUMN, authors, TITLE_COLUMN, title, -1 );
}
}
// called when window is closed
void on_window_main_destroy()
{
gtk_main_quit();
}
int main(int argc, char *argv[])
{
gtk_init(&argc, &argv);
// -- load builder
GtkBuilder* builder;
builder = gtk_builder_new();
gtk_builder_add_from_file (builder, "resources/ui/ref_search.glade", NULL);
gtk_builder_connect_signals(builder, NULL);
// -- Cell Renderer and fake data
init_reference_list(builder);
// -- Launch
GtkWidget *window;
window = GTK_WIDGET(gtk_builder_get_object(builder, "window_main"));
gtk_widget_show(window);
g_object_unref(builder);
gtk_main();
return 0;
}
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<object class="GtkEntryBuffer" id="search_buffer"/>
<object class="GtkWindow" id="window_main">
<property name="can_focus">False</property>
<property name="halign">baseline</property>
<property name="valign">baseline</property>
<property name="title" translatable="yes">Reference Manager</property>
<property name="resizable">False</property>
<property name="default_width">640</property>
<property name="default_height">480</property>
<signal name="destroy" handler="on_window_main_destroy" swapped="no"/>
<child type="titlebar">
<placeholder/>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkSearchEntry" id="search_bar">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="buffer">search_buffer</property>
<property name="primary_icon_name">edit-find-symbolic</property>
<property name="primary_icon_activatable">False</property>
<property name="primary_icon_sensitive">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">external</property>
<property name="shadow_type">in</property>
<property name="max_content_height">500</property>
<child>
<object class="GtkTreeView" id="tree_view">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="rules_hint">True</property>
<property name="enable_search">False</property>
<property name="show_expanders">False</property>
<property name="enable_grid_lines">horizontal</property>
<child internal-child="selection">
<object class="GtkTreeSelection"/>
</child>
<child>
<object class="GtkTreeViewColumn" id="authors">
<property name="resizable">True</property>
<property name="sizing">autosize</property>
<property name="title" translatable="yes">Author(s)</property>
<property name="expand">True</property>
<property name="clickable">True</property>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="title">
<property name="resizable">True</property>
<property name="sizing">autosize</property>
<property name="title" translatable="yes">Title</property>
<property name="expand">True</property>
<property name="clickable">True</property>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
</interface>
Apologies if I'm missing the obvious!
This might be closer to what you are looking for in the Glade file:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.2 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<object class="GtkListStore" id="liststore1">
<columns>
<!-- column-name authors -->
<column type="gchararray"/>
<!-- column-name titles -->
<column type="gchararray"/>
</columns>
<data>
<row>
<col id="0" translatable="yes">Me You Us Them All of us</col>
<col id="1" translatable="yes">A long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long title</col>
</row>
</data>
</object>
<object class="GtkEntryBuffer" id="search_buffer"/>
<object class="GtkWindow" id="window_main">
<property name="can_focus">False</property>
<property name="halign">baseline</property>
<property name="valign">baseline</property>
<property name="title" translatable="yes">Reference Manager</property>
<property name="resizable">False</property>
<property name="default_width">640</property>
<property name="default_height">480</property>
<signal name="destroy" handler="on_window_main_destroy" swapped="no"/>
<child type="titlebar">
<placeholder/>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkSearchEntry" id="search_bar">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="buffer">search_buffer</property>
<property name="primary_icon_name">edit-find-symbolic</property>
<property name="primary_icon_activatable">False</property>
<property name="primary_icon_sensitive">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">external</property>
<property name="shadow_type">in</property>
<property name="max_content_height">500</property>
<child>
<object class="GtkTreeView" id="tree_view">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="model">liststore1</property>
<property name="rules_hint">True</property>
<property name="enable_search">False</property>
<property name="show_expanders">False</property>
<property name="enable_grid_lines">horizontal</property>
<child internal-child="selection">
<object class="GtkTreeSelection"/>
</child>
<child>
<object class="GtkTreeViewColumn" id="authors">
<property name="resizable">True</property>
<property name="sizing">fixed</property>
<property name="title" translatable="yes">Author(s)</property>
<property name="expand">True</property>
<property name="clickable">True</property>
<child>
<object class="GtkCellRendererText">
<property name="ellipsize">middle</property>
</object>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="title">
<property name="resizable">True</property>
<property name="sizing">fixed</property>
<property name="title" translatable="yes">Title</property>
<property name="expand">True</property>
<property name="clickable">True</property>
<child>
<object class="GtkCellRendererText">
<property name="ellipsize">middle</property>
</object>
<attributes>
<attribute name="text">1</attribute>
</attributes>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
</interface>
Edit with another attempt:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<object class="GtkListStore" id="liststore1">
<columns>
<!-- column-name authors -->
<column type="gchararray"/>
<!-- column-name titles -->
<column type="gchararray"/>
</columns>
<data>
<row>
<col id="0" translatable="yes">Me You Us Them All of us</col>
<col id="1" translatable="yes">A long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long title</col>
</row>
</data>
</object>
<object class="GtkEntryBuffer" id="search_buffer"/>
<object class="GtkWindow" id="window_main">
<property name="width_request">250</property>
<property name="can_focus">False</property>
<property name="title" translatable="yes">Reference Manager</property>
<property name="resizable">False</property>
<property name="default_width">640</property>
<property name="default_height">480</property>
<signal name="destroy" handler="on_window_main_destroy" swapped="no"/>
<child type="titlebar">
<placeholder/>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkSearchEntry" id="search_bar">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="buffer">search_buffer</property>
<property name="primary_icon_name">edit-find-symbolic</property>
<property name="primary_icon_activatable">False</property>
<property name="primary_icon_sensitive">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">never</property>
<property name="shadow_type">in</property>
<property name="max_content_height">500</property>
<child>
<object class="GtkTreeView" id="tree_view">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="model">liststore1</property>
<property name="rules_hint">True</property>
<property name="enable_search">False</property>
<property name="show_expanders">False</property>
<property name="enable_grid_lines">horizontal</property>
<child internal-child="selection">
<object class="GtkTreeSelection"/>
</child>
<child>
<object class="GtkTreeViewColumn" id="authors">
<property name="resizable">True</property>
<property name="sizing">fixed</property>
<property name="min_width">25</property>
<property name="title" translatable="yes">Author(s)</property>
<property name="expand">True</property>
<property name="clickable">True</property>
<child>
<object class="GtkCellRendererText">
<property name="ellipsize">middle</property>
</object>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="title">
<property name="resizable">True</property>
<property name="min_width">25</property>
<property name="title" translatable="yes">Title</property>
<property name="expand">True</property>
<property name="clickable">True</property>
<child>
<object class="GtkCellRendererText">
<property name="ellipsize">middle</property>
</object>
<attributes>
<attribute name="text">1</attribute>
</attributes>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
</interface>
Related
I am using a GtkAboutDialog to open on a button click. It works fine on the first click but on the second click it just crashes. On the button clicked signal I am just using gtk_widget_show() to display the dialog. The about dialog is described in a .ui file
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.1 -->
<interface>
<requires lib="gtk+" version="3.24"/>
<object class="GtkAboutDialog" id="about_warehouse_dialog">
<property name="name">about_warehouse</property>
<property name="can-focus">False</property>
<property name="destroy-with-parent">True</property>
<property name="type-hint">dialog</property>
<property name="program-name">Պահեստ</property>
<property name="version">1.0</property>
<property name="copyright" translatable="yes">
text
</property>
<property name="authors">Grigor Sargsyan <Mr.G.Sargsyan#master-mind.llc>
Int Elligence Group <IntElligence#master-mind.llc></property>
<property name="documenters">Artur Tarasyan <Mr.Tarasyan#master-mind.llc></property>
<property name="translator-credits" translatable="yes">Grigor Sargsyan <Mr.G.Sargsyan#master-mind.llc> </property>
<property name="artists">Janik Tarverdyan <Mr.J.Tarverdyan#master-mind.llc></property>
<property name="logo">../../data/media/image/Logo/Logo_About.png</property>
<property name="wrap-license">True</property>
<property name="license-type">custom</property>
<child internal-child="vbox">
<object class="GtkBox">
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child internal-child="action_area">
<object class="GtkButtonBox">
<property name="can-focus">False</property>
<property name="layout-style">end</property>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
</child>
</object>
I am retrieving the GtkAboutDialog described there with a GtkBuilder object and assigning it to a pointer for which I am calling gtk_widget_show(). I am not sure why this happens. I have not defined any signals for destroying the object.
C code:
I am retrieving the object this way where main_wind_ob->pmenu_builder is the GtkBuilder object associated with the .ui file mentioned above.
main_wind_ob->about_dialog = GTK_WIDGET
(
gtk_builder_get_object
(
main_wind_ob->pmenu_builder,
"about_warehouse_dialog"
)
);
Here is the button clicked signal which is supposed to show the dialog.
static void
on_pmenu_about_dialog_clicked(GtkButton * button,
gpointer userdata)
{
#ifdef DEBUG
printf("\non_pmenu_about_dialog_clicked()\n");
#endif
mainwindow * main_wind = MAIN_WINDOW(userdata);
gtk_widget_show(main_wind->about_dialog);
}
I have two toggle buttons named RUN and KILL. When I toggle on (i.e. depress) the RUN button, I only want it to toggle off by depressing the KILL toggle button (NOT by toggling off the RUN button). I want any subsequent mouse clicks on the RUN button to do nothing unless the KILL button is depressed. Likewise, when the KILL button is toggled on, I only want it to toggle off by depressing the RUN button (again, NOT by toggling off the KILL button). I am not sure how to construct the event handlers that would bind the action of these two toggle buttons together. I am using GTK+ together with Glade and programming in C.
Since the GtkToggleButton is a generic button and it will toggle with all user interactions we must prevent it from toggling under certain conditions. In this case, the button after being toggled can't be toggled again on itself but via another toggle button. To achieve this, you must:
Prevent button events from toggling the button under certain conditions
Bind both buttons with inverted logic (mutually exclusive)
To achieve 1) we can connect a callback to the GtkWidget "button-press-event" signal and return according to the wanted conditions, with TRUE preventing the signal from propagating and FALSE otherwise.
Then, to handle 2), we can use g_object_bind_property for the GtkToggleButton "active" property with G_BINDING_INVERTED_BOOLEAN flag to get the desired behavior. Notice that we must set one of them active as a start condition.
So, a simple example could be:
#include <gtk/gtk.h>
gboolean on_toggle_button_press_event(GtkWidget *widget, GdkEventButton *event, gpointer user_data) {
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)) == TRUE) {
return TRUE;
}
return FALSE;
}
void on_run_toggle_active(GObject *obj, GParamSpec *pspec, gpointer user_data) {
g_return_if_fail (user_data != NULL);
GtkLabel *label = GTK_LABEL(user_data);
GtkToggleButton *button = GTK_TOGGLE_BUTTON(obj);
if (gtk_toggle_button_get_active(button) == TRUE) {
gtk_label_set_text (label, "Running...");
} else {
gtk_label_set_text (label, "Idle");
}
}
gint main(gint argc, gchar **argv) {
GtkLabel *status;
GtkWindow *window;
GtkBuilder *builder;
GtkToggleButton *run_toggle;
GtkToggleButton *kill_toggle;
gtk_init(&argc, &argv);
builder = gtk_builder_new_from_file("gui.ui");
window = GTK_WINDOW(gtk_builder_get_object(builder, "window1"));
status = GTK_LABEL(gtk_builder_get_object(builder, "status"));
run_toggle = GTK_TOGGLE_BUTTON(gtk_builder_get_object(builder, "toggle"));
kill_toggle = GTK_TOGGLE_BUTTON(gtk_builder_get_object(builder, "kill"));
g_object_bind_property (G_OBJECT(run_toggle), "active", G_OBJECT(kill_toggle), "active", G_BINDING_INVERT_BOOLEAN);
g_object_bind_property (G_OBJECT(kill_toggle), "active", G_OBJECT(run_toggle), "active", G_BINDING_INVERT_BOOLEAN);
g_signal_connect(G_OBJECT(run_toggle), "button-press-event", G_CALLBACK(on_toggle_button_press_event), NULL);
g_signal_connect(G_OBJECT(kill_toggle), "button-press-event", G_CALLBACK(on_toggle_button_press_event), NULL);
g_signal_connect(G_OBJECT(run_toggle), "notify::active", G_CALLBACK(on_run_toggle_active), status);
g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);
gtk_widget_show_all(GTK_WIDGET(window));
gtk_main();
return 0;
}
To simplify, I've outlined the user interface with glade (gui.ui):
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.20.2 -->
<interface>
<requires lib="gtk+" version="3.18"/>
<object class="GtkWindow" id="window1">
<property name="can_focus">False</property>
<child>
<object class="GtkGrid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="row_spacing">20</property>
<child>
<object class="GtkLabel" id="status">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Idle</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
<property name="width">2</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkToggleButton" id="toggle">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="focus_on_click">False</property>
<property name="receives_default">True</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">3</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">media-playback-start-symbolic</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Run</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkToggleButton" id="kill">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="active">True</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">3</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">user-trash-symbolic</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Kill</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<style>
<class name="linked"/>
</style>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
<property name="width">2</property>
</packing>
</child>
</object>
</child>
<child type="titlebar">
<placeholder/>
</child>
</object>
<object class="GtkSizeGroup">
<widgets>
<widget name="label1"/>
<widget name="label2"/>
</widgets>
</object>
</interface>
Compile with:
gcc -o main main.c `pkg-config --cflags --libs gtk+-3.0`
And the output should be something like this:
The Toggle Buttons are mutually exclusive and pressing them while active won't have any visual effect.
PS: No keyboard handling is assumed, otherwise we must handle those signals and act accordingly.
It's only possible to pass one variable in a callback function. So we have to built structures. I'm okay with this but how to do with Treeview and Treemodel/Liststore ?
I want to avoid global variables. This test program should get the content of the selected row displayed in the EntryBoxes. I don't know if i'm wrong making the struct including the Treeview or if there's something wrong inside the function. I get segfault.
What would be the correct way to deal with that ?
#include <gtk/gtk.h>
typedef struct {
GtkWidget *ent_date;
GtkWidget *ent_lib;
GtkWidget *ent_mont;
GtkTreeView *treeview;
} app_widgets;
enum
{
DATE_COLUMN,
LIBELLE_COLUMN,
MONTANT_COLUMN,
N_COLUMN
};
void on_window_main_destroy()
{
gtk_main_quit();
}
void on_treeview_selection1_changed (GtkTreeSelection *treeselection, app_widgets *app_wid) {
gchar value[3];
GtkTreeIter iter;
GtkTreePath *path;
//GtkTreeView *treeview = (GtkTreeView *)app_wid->treeview;
GtkListStore *store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(app_wid->treeview)));
gtk_tree_view_get_cursor (app_wid->treeview, &path, NULL);
gtk_tree_model_get_iter (GTK_TREE_MODEL(store), &iter, path);
gtk_tree_path_free (path);
if (gtk_tree_selection_get_selected(treeselection, &store, &iter))
{
gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, DATE_COLUMN, &value[0], LIBELLE_COLUMN, &value[1],MONTANT_COLUMN, &value[2], -1);
}
gtk_entry_set_text(GTK_ENTRY(app_wid->ent_date), value[0]);
gtk_entry_set_text(GTK_ENTRY(app_wid->ent_lib), value[1]);
gtk_entry_set_text(GTK_ENTRY(app_wid->ent_mont), value[2]);
g_free(value);
}
int main(int argc, char *argv[])
{
GtkBuilder *builder;
app_widgets *widgets = g_slice_new(app_widgets);
gtk_init(&argc, &argv);
builder = gtk_builder_new();
gtk_builder_add_from_file (builder, "test.glade", NULL);
widgets->ent_date = GTK_WIDGET(gtk_builder_get_object(builder, "entry_date"));
widgets->ent_lib = GTK_WIDGET(gtk_builder_get_object(builder, "entry_lib"));
widgets->ent_mont = GTK_WIDGET(gtk_builder_get_object(builder, "entry_mont"));
widgets->treeview = GTK_TREE_VIEW(gtk_builder_get_object(builder, "treeview1"));
gtk_builder_connect_signals(builder, NULL);
gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(builder, "window1")));
g_object_unref(builder);
gtk_main();
g_slice_free(app_widgets, widgets);
return 0;
}
Here's the glade file:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.18.3 -->
<interface>
<requires lib="gtk+" version="3.12"/>
<object class="GtkListStore" id="liststore1">
<columns>
<!-- column-name Date -->
<column type="gchararray"/>
<!-- column-name Libellé -->
<column type="gchararray"/>
<!-- column-name Montant -->
<column type="gchararray"/>
</columns>
<data>
<row>
<col id="0" translatable="yes">20.05.2017</col>
<col id="1" translatable="yes">Something - here</col>
<col id="2" translatable="yes">30.20</col>
</row>
<row>
<col id="0" translatable="yes">25.06.2017</col>
<col id="1" translatable="yes">Something else - overthere</col>
<col id="2" translatable="yes">24.90</col>
</row>
<row>
<col id="0" translatable="yes">11.08.2017</col>
<col id="1" translatable="yes">Third thing - lala</col>
<col id="2" translatable="yes">5.15</col>
</row>
</data>
</object>
<object class="GtkWindow" id="window1">
<property name="can_focus">False</property>
<property name="margin_left">5</property>
<property name="margin_right">5</property>
<property name="margin_top">5</property>
<property name="margin_bottom">5</property>
<property name="window_position">center</property>
<child>
<object class="GtkBox" id="box1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkScrolledWindow" id="scrolledwindow1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkTreeView" id="treeview1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="model">liststore1</property>
<child internal-child="selection">
<object class="GtkTreeSelection" id="treeview-selection1">
<signal name="changed" handler="on_treeview_selection1_changed" swapped="no"/>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="treeviewcolumn1">
<property name="resizable">True</property>
<property name="fixed_width">70</property>
<property name="title" translatable="yes">Date</property>
<child>
<object class="GtkCellRendererText" id="cellrenderertext1"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="treeviewcolumn2">
<property name="resizable">True</property>
<property name="title" translatable="yes">Libellé</property>
<child>
<object class="GtkCellRendererText" id="cellrenderertext2"/>
<attributes>
<attribute name="text">1</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="treeviewcolumn3">
<property name="resizable">True</property>
<property name="title" translatable="yes">Montant</property>
<child>
<object class="GtkCellRendererText" id="cellrenderertext3"/>
<attributes>
<attribute name="text">2</attribute>
</attributes>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkBox" id="box2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkBox" id="box_date">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Date</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="entry_date">
<property name="visible">True</property>
<property name="can_focus">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox" id="box_lib">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Lib</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="entry_lib">
<property name="visible">True</property>
<property name="can_focus">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkBox" id="box_mont">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel" id="label3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Montant</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="entry_mont">
<property name="visible">True</property>
<property name="can_focus">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
</object>
</interface>
First thing, you cannot use gtk_builder_connect_signals(builder, NULL); and then expect the callback handlers to receive user data.
You should have passed the widgets structure:
gtk_builder_connect_signals(builder, widgets);
Second thing, you over complicated the selection callback. The GtkTreeSelection instance will give you the model when you call gtk_tree_selection_get_selected. Then you must understand that this last function will "not work if you use selection GTK_SELECTION_MULTIPLE".
Also notice that gtk_tree_model_get should take pointers to char/gchar which will then point to newly allocated copies of the model content (means they must be freed afterwards).
So, your code should be something like this:
#include <gtk/gtk.h>
typedef struct {
GtkWidget *ent_date;
GtkWidget *ent_lib;
GtkWidget *ent_mont;
GtkTreeView *treeview;
} app_widgets;
enum
{
DATE_COLUMN,
LIBELLE_COLUMN,
MONTANT_COLUMN,
N_COLUMN
};
void on_window_main_destroy()
{
gtk_main_quit();
}
void on_treeview_selection1_changed (GtkTreeSelection *treeselection, app_widgets *app_wid) {
gchar *a,*b,*c;
GtkTreeIter iter;
GtkTreeModel *model;
if (gtk_tree_selection_get_selected(treeselection, &model, &iter))
{
gtk_tree_model_get(model, &iter, DATE_COLUMN, &a, LIBELLE_COLUMN, &b,MONTANT_COLUMN, &c, -1);
}
gtk_entry_set_text(GTK_ENTRY(app_wid->ent_date), a);
gtk_entry_set_text(GTK_ENTRY(app_wid->ent_lib), b);
gtk_entry_set_text(GTK_ENTRY(app_wid->ent_mont), c);
g_free(a);
g_free(b);
g_free(c);
}
int main(int argc, char *argv[])
{
GtkBuilder *builder;
app_widgets *widgets = g_slice_new(app_widgets);
gtk_init(&argc, &argv);
builder = gtk_builder_new();
gtk_builder_add_from_file (builder, "test.glade", NULL);
widgets->ent_date = GTK_WIDGET(gtk_builder_get_object(builder, "entry_date"));
widgets->ent_lib = GTK_WIDGET(gtk_builder_get_object(builder, "entry_lib"));
widgets->ent_mont = GTK_WIDGET(gtk_builder_get_object(builder, "entry_mont"));
widgets->treeview = GTK_TREE_VIEW(gtk_builder_get_object(builder, "treeview1"));
gtk_builder_connect_signals(builder, widgets);
gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(builder, "window1")));
g_object_unref(builder);
gtk_main();
g_slice_free(app_widgets, widgets);
return 0;
}
Problem
I have a problem where closing a widget with the delete event, via gtk_widget_hide_on_delete fails to show the menu widget again via a swapped gtk_widget_show_all with the corresponding widget passed to it as an argument.
Background
I'm creating a program consisting of a selection menu with a number of button widgets. Pressing one button will hide the menu, and show a window widget containing a label and a TextEntry, the delete event of this window widget will hide the widget, and show the menu again.
Example program
I've created a minimal example for this problem. The code simply loads the ui via GtkBuilder and then enters the main gtk loop.
I rely on gtk_widget_show_all, gtk_widget_hide and gtk_widget_hide_on_delete, but when I close the exercise widget using the delete-event, the window disappears, but the menu widget isn't shown.
#include <gtk/gtk.h>
#include <stdio.h>
int main(int argc, char **argv)
{
GtkBuilder * builder;
GtkWidget * menu;
GError *error = NULL;
gtk_init(&argc, &argv);
builder = gtk_builder_new();
if (!gtk_builder_add_from_file(builder, "example.glade", &error)) {
g_warning("%s", error->message);
g_free(error);
fprintf(stderr, "Failed to load build file");
}
menu = (GtkWidget *) gtk_builder_get_object(builder, "menu");
gtk_builder_connect_signals(builder, NULL);
gtk_widget_show(menu);
gtk_main();
return 0;
}
The XML file example.glade has been created using Glade.
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.16.1 -->
<interface>
<requires lib="gtk+" version="3.10"/>
<object class="GtkWindow" id="exercise">
<property name="can_focus">False</property>
<property name="window_position">center</property>
<signal name="delete-event" handler="gtk_widget_hide_on_delete" swapped="no"/>
<signal name="delete-event" handler="gtk_widget_show_all" object="menu" after="yes" swapped="yes"/>
<child>
<object class="GtkGrid" id="grid2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkEntry" id="entry1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hexpand">True</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
<property name="width">1</property>
<property name="height">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="label" translatable="yes">A window where stuff will happen.</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
<property name="width">1</property>
<property name="height">1</property>
</packing>
</child>
</object>
</child>
</object>
<object class="GtkWindow" id="menu">
<property name="can_focus">False</property>
<property name="window_position">center</property>
<signal name="destroy" handler="gtk_main_quit" swapped="no"/>
<child>
<object class="GtkGrid" id="grid1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkButton" id="button1">
<property name="label" translatable="yes">button1</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<signal name="clicked" handler="gtk_widget_hide" object="menu" swapped="yes"/>
<signal name="clicked" handler="gtk_widget_show_all" object="exercise" swapped="yes"/>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
<property name="width">1</property>
<property name="height">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button2">
<property name="label" translatable="yes">button2</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<signal name="clicked" handler="gtk_widget_hide" object="menu" swapped="yes"/>
<signal name="clicked" handler="gtk_widget_show_all" object="exercise" swapped="yes"/>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
<property name="width">1</property>
<property name="height">1</property>
</packing>
</child>
</object>
</child>
</object>
</interface>
The problem is in these two lines of your Glade file:
<signal name="delete-event" handler="gtk_widget_hide_on_delete" swapped="no"/>
<signal name="delete-event" handler="gtk_widget_show_all" object="menu" after="yes" swapped="yes"/>
Looking at the manual page of gtk_widget_hide_on_delete(), we see:
Utility function; intended to be connected to the “delete-event” signal on a GtkWindow. The function calls gtk_widget_hide() on its argument, then returns TRUE.
If we look at the delete-event signal, we see:
Returns
TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
This means that after the gtk_widget_hide_on_delete() is called, TRUE is returned, and this stops the GTK runtime from calling gtk_widget_show_all().
To achieve what you want, you can use a custom-defined handler, as shown below:
Remove that two lines and replace with the following:
<signal name="delete-event" handler="my_custom_func" object="menu" swapped="no"/>
Add your custom handler to the C file:
G_MODULE_EXPORT gboolean
my_custom_func(GtkWidget *w, GdkEvent *e, gpointer u) {
gtk_widget_hide(w);
gtk_widget_show_all(GTK_WIDGET(u));
return TRUE;
}
I've been teaching myself how to code in C and utilize GTK for writing applications in Linux, using Glade to design the UI before implementing it. I've been trying to utilize a GtkTreeView coupled with a GtkListStore to display data, but I seem to be running into issues. I can get my application to launch fine and it shows the window and dialog correctly, but I cannot figure out how to add rows of data to the List Store programmatically and have them appear in the Tree View; most tutorials I find seem to prefer to make the rows in Glade, or to design the whole interface through the code. With the code as it is I receive no errors when running the program, but I cannot see anything being added in GtkTreeView. I don't see any blank rows being added either.
By writing some code to forcibly generate an error, I can see that the signal for postingButton is being connected (I think) so that should be fine. I'm just missing something in my actual implementation of GtkTreeView. If anyone can help me out, I'd greatly appreciate it!
Edit: The GtkEntries that are present will be implemented later; I'm just trying to get data to show up at all.
C Code:
/* I'd give objects better names normally, no worries!
* Just goofing around for now.*/
#include <gtk-3.0/gtk/gtk.h> // Needed for interface.
#include <gtk-3.0/gdk/gdk.h>
#include <glib-2.0/glib-object.h>
void on_mainWindow_destroy(GObject *object, gpointer user_data)
{
gtk_main_quit();
}
void on_stupidButton_clicked(GtkButton *button, gpointer *user_data)
{
gtk_dialog_run(GTK_DIALOG(user_data));
}
void on_postingButton_clicked(GtkButton *button, gpointer *user_data)
{
GtkListStore *liststore1;
GtkWidget *treeview1; // I've tried defining this as a GtkTreeView as well.
GtkTreeIter iter;
GtkBuilder *listStoreBuilder;
listStoreBuilder = gtk_builder_new();
gtk_builder_add_from_file(listStoreBuilder,
"../testing_interface.glade", 0);
treeview1 = GTK_WIDGET(gtk_builder_get_object(listStoreBuilder,
"treeview1")); // I'd change this to GTK_TREE_VIEW if the
// above is a GtkTreeView.
liststore1 = GTK_LIST_STORE(
gtk_tree_view_get_model((GtkTreeView *)treeview1));
gtk_list_store_append(liststore1, &iter);
gtk_list_store_set(liststore1, &iter, 0, "c", 1, "d", -1);
gtk_builder_connect_signals(listStoreBuilder, 0);
g_object_unref(G_OBJECT(listStoreBuilder));
g_object_unref(G_OBJECT(liststore1));
}
void on_cancelButton_clicked(GtkButton *button, gpointer *user_data)
{
gtk_widget_destroy((GtkWidget *)user_data);
}
int main(int argc, char *argv[])
{
GtkBuilder *builder;
GtkWidget *mainWindow, *dumbDialog;
GtkButton *stupidButton;
gtk_init(&argc, &argv);
builder = gtk_builder_new();
gtk_builder_add_from_file(builder, "../testing_interface.glade",
0);
mainWindow = GTK_WIDGET(gtk_builder_get_object(builder, "mainWindow"));
stupidButton = GTK_BUTTON(gtk_builder_get_object(builder, "stupidButton"));
dumbDialog = GTK_WIDGET(gtk_builder_get_object(builder, "dumbDialog"));
gtk_builder_connect_signals(builder, 0);
g_object_unref(G_OBJECT(builder));
gtk_widget_show(mainWindow);
gtk_main();
return 0;
}
Glade File (testing_interface.glade):
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<!-- interface-requires gtk+ 3.0 -->
<object class="GtkDialog" id="dumbDialog">
<property name="can_focus">False</property>
<property name="border_width">5</property>
<property name="type_hint">dialog</property>
<child internal-child="vbox">
<object class="GtkBox" id="dialog-vbox1">
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child internal-child="action_area">
<object class="GtkButtonBox" id="dialog-action_area1">
<property name="can_focus">False</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="postingButton">
<property name="label" translatable="yes">Post</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_action_appearance">False</property>
<signal name="clicked" handler="on_postingButton_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="cancelButton">
<property name="label" translatable="yes">Cancel</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_action_appearance">False</property>
<signal name="clicked" handler="on_cancelButton_clicked" object="dumbDialog" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox" id="box2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkEntry" id="entry1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">●</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="entry2">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">●</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
<action-widgets>
<action-widget response="0">postingButton</action-widget>
<action-widget response="0">cancelButton</action-widget>
</action-widgets>
</object>
<object class="GtkListStore" id="liststore1">
<columns>
<!-- column-name Testing -->
<column type="gchararray"/>
<!-- column-name Testing1 -->
<column type="gchararray"/>
</columns>
</object>
<object class="GtkWindow" id="mainWindow">
<property name="can_focus">False</property>
<signal name="destroy" handler="on_mainWindow_destroy" swapped="no"/>
<child>
<object class="GtkBox" id="box1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkTreeView" id="treeview1">
<property name="height_request">183</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="model">liststore1</property>
<child internal-child="selection">
<object class="GtkTreeSelection" id="treeview-selection1"/>
</child>
<child>
<object class="GtkTreeViewColumn" id="testing1Col">
<property name="title" translatable="yes">column</property>
<child>
<object class="GtkCellRendererText" id="cellrenderertext1"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="testing2Col">
<property name="title" translatable="yes">column</property>
<child>
<object class="GtkCellRendererText" id="cellrenderertext2"/>
<attributes>
<attribute name="text">1</attribute>
</attributes>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="stupidButton">
<property name="label" translatable="yes">button</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_action_appearance">False</property>
<signal name="clicked" handler="on_stupidButton_clicked" object="dumbDialog" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
</interface>
Your code that appends rows to the tree view is basically okay, but several problems prevent it from working.
You are creating and populating a new builder on each entry to on_postingButton_clicked. This is obviously incorrect, because it means that you're creating a new tree and a new store on each click of the Post button. This is easily fixed by sending treeview1 as user_data to the on_postingButton_clicked callback. You do that already in dialog, so I simply modified <signal name="clicked" handler="on_postingButton_clicked" ...> in your XML to also include object="treeview1".
You are being too liberal with g_object_unref. gtk_tree_view_get_model doesn't increase the refcount of its model, so you shouldn't unref the liststore you get. Unrefing the builder in main is probably a bad idea if you want to pass it around and retrieve objects from it (and it's a singleton anyway).
You're supposed to #include <gtk/gtk.h>, without the intervening gtk-3.0 directory. If your compilation fails without that, you are probably not setting up pkg-flags correctly.
Here is a modified version of your code that works for me. It requires XML to be modified as described above.
/* compile with:
gcc -O2 -Wall glade-test.c $(pkg-config gtk+-3.0 gmodule-export-2.0 --cflags --libs) */
#include <gtk/gtk.h>
#include <gdk/gdk.h>
#include <glib-object.h>
void on_mainWindow_destroy(GObject *object, gpointer user_data)
{
gtk_main_quit();
}
void on_stupidButton_clicked(GtkButton *button, gpointer *user_data)
{
gtk_dialog_run(GTK_DIALOG(user_data));
}
void on_postingButton_clicked(GtkButton *button, gpointer *user_data)
{
GtkTreeIter iter;
GtkTreeView *treeview1 = GTK_TREE_VIEW(user_data);
GtkListStore *liststore1 = GTK_LIST_STORE(gtk_tree_view_get_model(treeview1));
gtk_list_store_append(liststore1, &iter);
gtk_list_store_set(liststore1, &iter, 0, "c", 1, "d", -1);
}
void on_cancelButton_clicked(GtkButton *button, gpointer *user_data)
{
gtk_widget_destroy((GtkWidget *)user_data);
}
int main(int argc, char *argv[])
{
GtkBuilder *builder;
gtk_init(&argc, &argv);
builder = gtk_builder_new();
gtk_builder_add_from_file(builder, "testing_interface.glade", 0);
gtk_builder_connect_signals(builder, 0);
gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(builder, "mainWindow")));
g_object_unref(G_OBJECT(builder));
gtk_main();
return 0;
}