GTK+ Forums

Discussion forum for GTK+ and Programming. Ask questions, troubleshoot problems, view and post example code, or express your opinions.
It is currently Wed Sep 03, 2014 2:07 am

All times are UTC




Post new topic Reply to topic  [ 8 posts ] 
Author Message
 Post subject: Returning a value from callback function
PostPosted: Sun Jan 28, 2007 2:34 pm 
Offline

Joined: Sun Jan 28, 2007 1:48 am
Posts: 4
Hi,

I am making my first GTK program with C and it consists of one combobox, one button and one label. The idea is that when the button is pressed the value in the combobox is sent to button callback function. Inside the callback function the value is passed to another function which in turn returns a value depending on what combobox value was passed to it.

In the main function I have:
Code:
    ...
    /* Put combo_box entry in a string */
    const char *string;
    string = gtk_entry_get_text (GTK_ENTRY (GTK_COMBO (combo_box)->entry));

    /* Attach a signal handler to the button */
    g_signal_connect (G_OBJECT (button), "clicked",
                      G_CALLBACK (callback_button_pressed), (gpointer) string);
   ...


And the callback function is like this:
Code:
/* Callback for button pressing */
static void callback_button_pressed( GtkWidget *widget, gpointer data)
{
char returnString[50];
aFunctionWhichModifiesTheReturnString(returnString);
g_print("With the value %s the returning value was %s", (gchar *) data, returnString); /* this works well */
}


However, I don't understand how the returnString can be shown in my program's label instead of the g_print's stdout. One solution would be to use a global variable, but using one would be a generally bad idea. From surfing this forum I got the idea that I should use structures and pack the combobox and the label widgets into it and pass the struct to the button callback. Is that the "right way" to use GTK widgets?

Another question conserning the same issue: From http://developer.gnome.org/doc/API/2.0/glib/glib-Warnings-and-Assertions.html I got the idea that there is a way to redirect the g_print and g_printerr from stdout to a new print handler (g_set_print_handler). Could I show g_print messages in my program's label field and if so, how that is going to happen (could someone post a brief example?). Would it be a "wrong way" to code GTK programs?


Top
 Profile  
 
 Post subject:
PostPosted: Sun Jan 28, 2007 5:16 pm 
Offline
Never Seen the Sunlight

Joined: Wed Sep 21, 2005 3:07 am
Posts: 384
Location: Fairfax, Virginia
In your first code, it would much much more sense to just do the following. Pass the combo box to the callback function (not the string). g_object_add_data() adds the GtkLabel widget (label) to the string table.

Code:
...
    /* Attach a signal handler to the button */
    g_signal_connect (G_OBJECT (button), "clicked",
                      G_CALLBACK (callback_button_pressed), (gpointer) combo_box);
    g_object_add_data (G_OBJECT (combo_box), "label", (gpointer) label);
   ...


In the callback function, do the following. Do not case a const gchar*. Just send the const to the function. Return a gchar* from the function. You can create a new gchar* with g_strdup_printf(). This must be freed with g_free()!

Code:
/* Callback for button pressing */
static void callback_button_pressed( GtkWidget *widget, GtkComboBox *combo_box)
{
  const gchar *str;
  gchar *returnString;
  GtkWidget *label;

  returnString = aFunctionWhichReturnsAString (str);
  label = GTK_WIDGET (g_object_get_data (G_OBJECT (combo_box), "label"));

  str = gtk_entry_get_text (GTK_ENTRY (GTK_COMBO (combo_box)->entry));
  g_print ("With the value %s the returning value was %s", str, returnString);
  gtk_label_set_text (GTK_LABEL (label), returnString);
  g_free (returnString);
}


In this callback function, g_object_get_data() retrieves the GtkLabel, which was added to the combo box's string-data table. You can then set the label's text with the returned string. However, with more widgets, the structure method is the correct way to do it.

As for your second question, I'm not really sure. I would recommend just calling your own functions instead of calling g_print(). However, this isn't really the thing you should do. Errors output by GTK+ are meant to be in the terminal so that they can be read if a program crashes ...

_________________
Andrew Krause

Foundations of GTK+ Development: Buy now for only $31.49!


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jan 30, 2007 12:06 am 
Offline

Joined: Sun Jan 28, 2007 1:48 am
Posts: 4
openldev wrote:
However, with more widgets, the structure method is the correct way to do it.


Thanks, now I got the program working with one label and one combo box.

Now I want to pack in a couple of more widgets and probably should use the structure method. Now if we think about previous example and assume that there is an image widget alongside with the label and combo box mentioned before (and the image is returned from other function as well), how different the code would be? I would appreciate an example or a link to a good and explanatory web site. Particularly I'm interested in how one can reference widgets which are inside a structure and how the struct is passed to the function (and referenced in the function).


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jan 30, 2007 12:26 am 
Offline
Never Seen the Sunlight

Joined: Wed Sep 21, 2005 3:07 am
Posts: 384
Location: Fairfax, Virginia
Well, you would first need to define a structure as such:

Code:
typdedef struct
{
  GtkWidget *combo_box, *label, *image;
} AppWidgets;


Then, in your application, you need to create a new AppWidgets object. This can be sent with g_signal_connect().

Code:
...
AppWidgets *w = g_slice_new (AppWidgets);

/* Attach a signal handler to the button */
g_signal_connect (G_OBJECT (button), "clicked",
                  G_CALLBACK (callback_button_pressed), (gpointer) w);
...


The callback function, accepts the structure as the third parameter. You can access the widgets with w->widgetname. It is basically standard C programming ...

Code:
/* Callback for button pressing */
static void callback_button_pressed (GtkWidget *widget, GtkComboBox *combo_box, AppWidgets *w)
{
  const gchar *str;
  gchar *returnString;

  returnString = aFunctionWhichReturnsAString (str);

  str = gtk_entry_get_text (GTK_ENTRY (GTK_COMBO (w->combo_box)->entry));
  g_print ("With the value %s the returning value was %s", str, returnString);
  gtk_label_set_text (GTK_LABEL (w->label), returnString);
  g_free (returnString);
}

_________________
Andrew Krause

Foundations of GTK+ Development: Buy now for only $31.49!


Top
 Profile  
 
 Post subject:
PostPosted: Thu Feb 01, 2007 4:29 pm 
Offline

Joined: Sun Jan 28, 2007 1:48 am
Posts: 4
I might be the dumbest idiot in the planet, since I don't get my program working. :oops:

My programs dies to segmentation fault every time I try to handle data inside my AppWidgets structure.

Code:
/* Callback for button pressing */
static void callback_button_pressed (GtkWidget *widget, GtkComboBox *combo_box, AppWidgets *w)
{
   const gchar *str;
   str = gtk_entry_get_text (GTK_ENTRY (GTK_COMBO (w->combo_box)->entry));
   g_print("The string in from the combo box is %s!\n", str); /* program never gets in here... */
}


If the code above seems right, I am probably doing something wrong in my main function. I have defined a structure and created a new AppWidgets object, which I am sending with a g_signal_connect(). Am I missing something?


Top
 Profile  
 
 Post subject:
PostPosted: Thu Feb 01, 2007 4:43 pm 
Offline
Never Seen the Sunlight

Joined: Wed Sep 21, 2005 3:07 am
Posts: 384
Location: Fairfax, Virginia
Well, the first thing is that you should be casting it with GTK_COMBO_BOX(), not GTK_COMBO(). GtkCombo is depreciated and GtkComboBoxEntry is derived from GtkComboBox. As for the segmetation fault, you could try compiling your executable with -g in your compile line. Then, you can debug with GDB.

How you would do this is "gdb ./yourapplication". Then, type "run" when GDB opens. After your program crashes, type "where", which will give you a backtrace of exactly where the error occurred. If you have trouble reading the output, you can post it here & I will help. Also, typing "quit" in GDB will exit the debugger.

If we know exactly what line this is happening at, we can more easily track down the bug.

P.S. I am obligated to add that, if you are interested, I have a book on GTK+ coming out in April called Foundations of GTK+ Development. Either way, let me know if you need any more help tracking down this bug ...

_________________
Andrew Krause

Foundations of GTK+ Development: Buy now for only $31.49!


Top
 Profile  
 
 Post subject:
PostPosted: Fri Feb 02, 2007 12:26 am 
Offline

Joined: Sun Jan 28, 2007 1:48 am
Posts: 4
Ok, I changed the GTK_COMBO to GTK_COMBO_BOX with no luck - still the old familiar segmentation fault. Here's the code for my test program. It's only purpose is to make clear how multiple widgets can be passed to and used in a callback function.

Code:
#include <gtk/gtk.h>
#include <glib-object.h>

typedef struct {
        GtkWidget *label, *label2, *combo_box;
} AppWidgets;

static gboolean delete_event( GtkWidget *widget, GdkEvent  *event, gpointer data);
static void callback_button_pressed (GtkWidget *widget, GtkComboBox *combo_box, AppWidgets *w);

int main( int   argc,
          char *argv[] )
{
    /* Create needed widgets */
    GtkWidget *window;
    GtkWidget *table;
    GtkWidget *button;
    GtkWidget *image;
    GtkWidget *combo_box;
    GtkWidget *label;
    GtkWidget *label2;

    /* Create a new AppWidgets object */
    AppWidgets *w = g_slice_new (AppWidgets);   

    /* Initialize GTK */
    gtk_init (&argc, &argv);
   
    /* Create window and set a title and borders for it */
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    g_set_application_name("Test program");
    gtk_container_set_border_width (GTK_CONTAINER (window), 20);

    gtk_widget_set_size_request (window, 712, 400);

    /* Set a handler for delete_event that immediately
     * exits GTK. */
    g_signal_connect (G_OBJECT (window), "delete_event",
                      G_CALLBACK (delete_event), NULL);

    /* Create table and add it to window */
    table = gtk_table_new (5, 5, TRUE);
    gtk_container_add (GTK_CONTAINER (window), table);

    /* Create image and add it into the table */
    image = gtk_image_new_from_file("logo.png");
    gtk_table_attach_defaults (GTK_TABLE (table), image, 0, 5, 0,1);
    gtk_widget_show(image);

    /* Create the labels and attach them to the table */
    label = gtk_label_new ("This is the first label");
    gtk_table_attach_defaults(GTK_TABLE (table), label, 0, 3, 1, 2);
    gtk_widget_show (label);

    label2 = gtk_label_new ("This is the second label");
    gtk_table_attach_defaults (GTK_TABLE (table), label2, 0, 3, 2, 3);
    gtk_widget_show (label2);

    /* Create button and add it into the table */
    button = gtk_button_new_with_label("Push me");
    gtk_table_attach_defaults (GTK_TABLE (table), button, 3, 5, 1, 2);
    gtk_widget_show (button);

    /* Create combo box and add it into the table */
    combo_box = gtk_combo_box_new_text();

    gtk_combo_box_append_text (GTK_COMBO_BOX (combo_box), "Entry 1");
    gtk_combo_box_append_text (GTK_COMBO_BOX (combo_box), "Entry 2");
    gtk_combo_box_append_text (GTK_COMBO_BOX (combo_box), "Entry 3");
    gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box), 0);

    gtk_table_attach_defaults (GTK_TABLE (table), combo_box, 3, 5, 2, 3);
    gtk_widget_show (combo_box);

    /* Attach a signal handler to the button */
    g_signal_connect (G_OBJECT (button), "clicked",
                  G_CALLBACK (callback_button_pressed), (gpointer) w);

    /* Show all widgets in the Window */
    gtk_widget_show_all(GTK_WIDGET(window));
    gtk_main ();
   
    return 0;
}

/* Callback to close the window */
static gboolean delete_event( GtkWidget *widget, GdkEvent  *event, gpointer data)
{
    gtk_main_quit ();
    return FALSE;
}

/* Callback for button pressing */
static void callback_button_pressed (GtkWidget *widget, GtkComboBox *combo_box, AppWidgets *w)
{
  const gchar *str;
  str = gtk_combo_box_get_active_text (GTK_COMBO_BOX (w->combo_box));
  g_print("The text was %s\n", str);
}


I'm not sure if I should use "gtk_combo_box_get_active_text(GTK_BIN(GTK_COMBO_BOX (w->combo_box))->child)". Anyway, it also gives me segmentation fault.

When I run the debugger I get this kind of info:

Quote:
Program received signal SIGSEGV, Segmentation fault.
0x080490ae in callback_button_pressed (widget=0x80806e0, combo_box=0x804bf00,
w=0x0) at main2.c:98
98 str = gtk_combo_box_get_active_text (GTK_COMBO_BOX (w->combo_box));
(gdb) where
#0 0x080490ae in callback_button_pressed (widget=0x80806e0,
combo_box=0x804bf00, w=0x0) at main2.c:98
#1 0xb79ae423 in g_cclosure_marshal_VOID__VOID ()
from /usr/lib/libgobject-2.0.so.0
#2 0xb79a279f in g_closure_invoke () from /usr/lib/libgobject-2.0.so.0
#3 0xb79b12ea in g_signal_stop_emission () from /usr/lib/libgobject-2.0.so.0
#4 0xb79b2b19 in g_signal_emit_valist () from /usr/lib/libgobject-2.0.so.0
#5 0xb79b2e89 in g_signal_emit () from /usr/lib/libgobject-2.0.so.0
#6 0xb7cca49f in gtk_button_clicked () from /usr/lib/libgtk-x11-2.0.so.0
#7 0xb7ccbcda in _gtk_button_set_depressed ()
from /usr/lib/libgtk-x11-2.0.so.0
#8 0xb79ae423 in g_cclosure_marshal_VOID__VOID ()
from /usr/lib/libgobject-2.0.so.0
#9 0xb79a216f in g_cclosure_new_swap () from /usr/lib/libgobject-2.0.so.0
#10 0xb79a279f in g_closure_invoke () from /usr/lib/libgobject-2.0.so.0
#11 0xb79b15cc in g_signal_stop_emission () from /usr/lib/libgobject-2.0.so.0
#12 0xb79b2b19 in g_signal_emit_valist () from /usr/lib/libgobject-2.0.so.0
#13 0xb79b2e89 in g_signal_emit () from /usr/lib/libgobject-2.0.so.0
#14 0xb7cca41c in gtk_button_released () from /usr/lib/libgtk-x11-2.0.so.0
#15 0xb7ccb38c in _gtk_button_paint () from /usr/lib/libgtk-x11-2.0.so.0
#16 0xb7d8b8e0 in _gtk_marshal_BOOLEAN__BOXED ()
from /usr/lib/libgtk-x11-2.0.so.0
#17 0xb79a216f in g_cclosure_new_swap () from /usr/lib/libgobject-2.0.so.0
---Type <return> to continue, or q <return> to quit---
#18 0xb79a279f in g_closure_invoke () from /usr/lib/libgobject-2.0.so.0
#19 0xb79b19ce in g_signal_stop_emission () from /usr/lib/libgobject-2.0.so.0
#20 0xb79b2886 in g_signal_emit_valist () from /usr/lib/libgobject-2.0.so.0
#21 0xb79b2e89 in g_signal_emit () from /usr/lib/libgobject-2.0.so.0
#22 0xb7e6ddcf in gtk_widget_activate () from /usr/lib/libgtk-x11-2.0.so.0
#23 0xb7d8a05d in gtk_propagate_event () from /usr/lib/libgtk-x11-2.0.so.0
#24 0xb7d8a46b in gtk_main_do_event () from /usr/lib/libgtk-x11-2.0.so.0
#25 0xb7c2ddec in _gdk_events_queue () from /usr/lib/libgdk-x11-2.0.so.0
#26 0xb79328d6 in g_main_context_dispatch () from /usr/lib/libglib-2.0.so.0
#27 0xb7935996 in g_main_context_check () from /usr/lib/libglib-2.0.so.0
#28 0xb7935cb8 in g_main_loop_run () from /usr/lib/libglib-2.0.so.0
#29 0xb7d89765 in gtk_main () from /usr/lib/libgtk-x11-2.0.so.0
#30 0x08049082 in main (argc=1, argv=0xbff5fa44) at main2.c:81


What comes to your book, I definitely buy it if I decide to jump in to the world of GTK. I'm just wondering why there are no *good* tutorials about GTK either in printed form or online. For example, I got the idea to use the GTK_COMBO from the GTK.org's tutorial, which I assumed to be up-to-date...


Top
 Profile  
 
 Post subject:
PostPosted: Fri Feb 02, 2007 1:17 am 
Offline
Never Seen the Sunlight

Joined: Wed Sep 21, 2005 3:07 am
Posts: 384
Location: Fairfax, Virginia
Well, there are a few things wrong with this. First of all, the widgets in your structure should be referenced as follows. You are sending a structure of widgets that was never initialized in the example.

Code:
w->combo_box = gtk_combo_box_new_text();


Also, you have to create it with the following if you want to use the following. GtkComboBox and GtkComboBoxEntry are two separate widgets. Also, you can create a GtkComboBox with text or a GtkTreeModel. You can only create a GtkComboBoxEntry with a GtkTreeModel.

Code:
w->combo_box = gtk_combo_box_entry_new ();


Just a quick question. How much experience do you have with C programming? I would recommend that you read up a bit on how structures work in C, which will help you understand your segmentation fault. From there, I would recommend that you start with simpler widgets than GtkComboBox or GtkComboBoxEntry.

You should understand things like GtkButton, GtkLabel, GtkEntry, GtkCheckButton, GtkRadioButton, GtkToggleButton, GtkContainer (plus various container widgets) and others. Also, you should read up on GtkTreeModel, which is used to create the content of a GtkComboBoxEntry widget. You might want to check out the basics of this GtkTreeView tutorial: http://scentric.net/tutorial/

_________________
Andrew Krause

Foundations of GTK+ Development: Buy now for only $31.49!


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 8 posts ] 

All times are UTC


Who is online

Users browsing this forum: Google [Bot] and 2 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
cron
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group