How do we create a simple GUI app with glade and C? - c

As I am new to glade and C, I am trying to build a very simple GUI which has an entry box a label and a button. When the button is pressed whatever values present in the text box will we show it in label. This is my glade,
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<object class="GtkWindow" id="windows1">
<property name="can_focus">False</property>
<child>
<placeholder/>
</child>
<child>
<object class="GtkFixed">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkButton" id="button1">
<property name="label" translatable="yes">button</property>
<property name="width_request">100</property>
<property name="height_request">80</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="clicked" handler="on_clicked" swapped="no"/>
</object>
<packing>
<property name="x">182</property>
<property name="y">146</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="entry1">
<property name="width_request">100</property>
<property name="height_request">80</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
</object>
<packing>
<property name="x">68</property>
<property name="y">45</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label1">
<property name="width_request">100</property>
<property name="height_request">80</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">label</property>
</object>
<packing>
<property name="x">321</property>
<property name="y">44</property>
</packing>
</child>
</object>
</child>
</object>
</interface>
And this is the C logic which on button press prints clicked in terminal.
#include <gtk/gtk.h>
void on_clicked(GtkButton * b, gpointer data)
{
(void)b;
(void)data;
printf("clicked");
}
int main (int argc, char *argv[])
{
GtkBuilder *builder;
GtkWidget *window;
gtk_init(&argc, &argv);
builder = gtk_builder_new();
gtk_builder_add_from_file (builder, "example.glade", NULL);
window = GTK_WIDGET(gtk_builder_get_object(builder, "window1"));
gtk_builder_connect_signals(builder, NULL);
g_object_unref(builder);
gtk_widget_show(window);
gtk_main();
return 0;
}
// called when window is closed
void on_window_main_destroy()
{
gtk_main_quit();
}
I compiled the c code without any error using
gcc main.c $(pkg-config --cflags --libs gtk+-3.0) -o main -export-dynamic
But when I run I get this warning but no gui
Gtk-CRITICAL **: : gtk_widget_show: assertion 'GTK_IS_WIDGET (widget)' failed
How can I solve this problem? The second question is how can I fetch values from the text box and show it in label using c.

The error message you're getting is because your GtkWindow has id "windows1", while you're trying to fetch it using id "window1" (note that the former has an 's' in the middle, while the latter doesn't).
For your other question: you should fetch the GtkEntry widget (also using gtk_builder_get_object()) and save the resulting pointer somewhere. You can then fetch its contents once you are inside your callback.

Related

Getting properties of widgets from a glade file

I'm new to GTK and C. I started making UI for the embedded system. The interface should represent several tabs with information, switching between which is carried out by buttons on the device itself or by JS commands from a paired device (server). I am trying to implement this with GTK and Glade. I got a problem while using GtkStack. I need to pass the name of the stack page to the server so that the server sends back the information that will be displayed on the page.
I tried to get the Name of the page from the glade file using the function gtk_widget_style_get, but the compiler issues a warning ../gtk+-3.24.27/gtk/gtkwidget.c:13324: widget class 'GtkStack' has no property named 'title' and the program displays "garbage" instead of the page name. I also tried to get the "label" of the button. gtk_widget_style_get(btn_1, "title", &temp, NULL) The result was the same.
Here is the test code I am experimenting with
main.c
#include <gtk/gtk.h>
#define UI_FILE "for_test.glade"
GtkBuilder *builder;
GtkWidget *window;
GtkWidget *stack;
GtkWidget *fix_1;
GtkWidget *lbl_1;
GtkWidget *btn_1;
GtkWidget *fix_2;
GtkWidget *lbl_2;
GtkWidget *btn_2;
void
on_btn_1_clicked(GtkWidget *widget)
{
gchar *temp[100];
gtk_widget_style_get(stack, "title", &temp, NULL);
gtk_label_set_text(GTK_LABEL(lbl_1), *temp);
}
void
on_window_destroy()
{
gtk_main_quit();
}
int
main (int argc, char *argv[])
{
gtk_init(&argc, &argv);
builder = gtk_builder_new_from_file(UI_FILE);
window = GTK_WIDGET(gtk_builder_get_object(builder, "window"));
stack = GTK_WIDGET(gtk_builder_get_object(builder, "stack"));
fix_1 = GTK_WIDGET(gtk_builder_get_object(builder, "fix_1"));
lbl_1 = GTK_WIDGET(gtk_builder_get_object(builder, "lbl_1"));
btn_1 = GTK_WIDGET(gtk_builder_get_object(builder, "btn_1"));
fix_1 = GTK_WIDGET(gtk_builder_get_object(builder, "fix_1"));
lbl_2 = GTK_WIDGET(gtk_builder_get_object(builder, "lbl_2"));
btn_2 = GTK_WIDGET(gtk_builder_get_object(builder, "btn_2"));
g_signal_connect(window, "destroy", G_CALLBACK(on_window_destroy), NULL);
g_signal_connect(btn_1, "clicked", G_CALLBACK(on_btn_1_clicked), NULL);
//g_signal_connect(btn_2, "clicked", G_CALLBACK(on_btn_2_clicked), NULL);
gtk_builder_connect_signals(builder, NULL);
g_object_unref(builder);
gtk_widget_show(window);
gtk_main();
return 0;
}
for_test.glade
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.2 -->
<interface>
<requires lib="gtk+" version="3.24"/>
<object class="GtkWindow" id="window">
<property name="can-focus">False</property>
<property name="default-width">100</property>
<property name="default-height">200</property>
<signal name="destroy" handler="on_window_destroy" swapped="no"/>
<child>
<object class="GtkStack" id="stack">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkFixed" id="fix_1">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkButton" id="btn_1">
<property name="label" translatable="yes">button 1</property>
<property name="width-request">100</property>
<property name="height-request">80</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<signal name="clicked" handler="on_btn_1_clicked" swapped="no"/>
</object>
<packing>
<property name="y">100</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="lbl_1">
<property name="width-request">100</property>
<property name="height-request">80</property>
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">label</property>
</object>
</child>
</object>
<packing>
<property name="name">page0</property>
<property name="title" translatable="yes">page0</property>
</packing>
</child>
<child>
<object class="GtkFixed" id="fix_2">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkButton" id="btn_2">
<property name="label" translatable="yes">button 2</property>
<property name="width-request">100</property>
<property name="height-request">80</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<signal name="clicked" handler="on_btn_2_clicked" swapped="no"/>
</object>
<packing>
<property name="y">100</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="lbl_2">
<property name="width-request">100</property>
<property name="height-request">80</property>
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">label</property>
</object>
</child>
</object>
<packing>
<property name="name">page1</property>
<property name="title" translatable="yes">page1</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
</interface>
I suspect that I am using the wrong function to get the properties of the stackab page, but I haven't found another way to get them. Where did I go wrong?
Here is one of the solutions:
GValue k = {0,};
g_value_init(&k, G_TYPE_STRING);
gtk_container_child_get_property(GTK_CONTAINER(stack), fix_1, "name", &k);
g_message("%s", g_value_get_string(&k));

Binding Toggle Buttons to each other using Glade & GTK+ (in C)

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.

GTK expanders one at at time

I have made a glade interface where there are three expanders. I only want one to be open at any given time. So when the signal "activate" is used it calls a function expandlights() and all other expanders should close. I cant figure out how to affect the other expanders from the function. below was my best try, its clearly very wrong. I'm SO new to this.
MAIN:
int main(int argc, char *argv[])
{
GtkBuilder *builder;
GtkWidget *window;
gtk_init(&argc, &argv);
builder = gtk_builder_new();
gtk_builder_add_from_file (builder, "interface.ui", NULL);
window = GTK_WIDGET(gtk_builder_get_object(builder, "window1"));
gtk_builder_connect_signals(builder, NULL);
g_object_unref(builder);
gtk_widget_show(window);
gtk_main();
return 0;
}
this is the function i attempted which clearly fails
void expandlights( GtkWidget *expander1,
GtkWidget *expander2,
GtkWidget *expander3)
{
gtk_expander_set_expanded(expander2, FALSE);
gtk_expander_set_expanded(expander3, FALSE);
}
I dont know if im on the right track or way off here. Could use a schoolin!
Glade file:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.18.3 -->
<interface>
<requires lib="gtk+" version="3.12"/>
<object class="GtkWindow" id="window1">
<property name="can_focus">False</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="GtkExpander" id="expander1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<signal name="activate" handler="expandlights" swapped="no"/>
<child>
<object class="GtkLabel" id="label4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">lighting stuff</property>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Lights</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkExpander" id="expander2">
<property name="visible">True</property>
<property name="can_focus">True</property>
<signal name="activate" handler="expandalarm" swapped="no"/>
<child>
<object class="GtkLabel" id="label5">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Alarm stuff</property>
</object>
</child>
<child type="label">
Your activate handler must have the signature defined for the activate signal.
void
expandlights (GtkExpander *expander, gpointer user_data);
To be able to modify the other expanders from this function you'll need to use the user_data pointer: typically it's made to point to a struct that contains pointers to all widgets you may need. You can set the pointer value with gtk_builder_connect_signals() in your initialization when using glade if I recall correctly.
You should be able to use the same handler for all three expanders if you code it carefully (if the expander is being expanded then unexpand all of the expanders except the one that emitted the signal). Note that when you call gtk_expander_set_expanded() the activate signal handler for that expander will be called. This shouldn't be a problem for your case but keep it in mind -- don't create a never-ending expand loop.

Trouble hiding and showing widgets in response to event

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;
}

Programmatically Adding Data to a GtkTreeView/GtkListStore Created in Glade 3.12.1

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;
}

Resources