GTK+ Forums

Discussion forum for GTK+ and Programming. Ask questions, troubleshoot problems, view and post example code, or express your opinions.
It is currently Sat Dec 20, 2014 5:12 am

All times are UTC




Post new topic Reply to topic  [ 11 posts ] 
Author Message
 Post subject: [SOLVED] g_signal_connect - Trying to understand.
PostPosted: Wed Jan 18, 2012 10:58 pm 
Offline
Familiar Face

Joined: Sun Jan 01, 2012 7:28 pm
Posts: 14
Location: Québec
I have these two buttons:
Code:
btn_forward = gtk_button_new_with_mnemonic ("_Forward");
  g_signal_connect_swapped (G_OBJECT(btn_forward),"clicked",
          G_CALLBACK(validate_position), (gpointer) 1);

  btn_reverse = gtk_button_new_with_mnemonic ("_Reverse");
  g_signal_connect_swapped (G_OBJECT(btn_forward),"clicked",
          G_CALLBACK(validate_position), (gpointer) -1);

Their goal is to make a stepper motor move forward and backward. Hence the 1 and -1 as the last parameter.
Each button calls the same function:
Code:
long validate_position(gpointer direction)
{
    const gchar* posn=gtk_entry_get_text(GTK_ENTRY (text_posn));
    long ret=atoi(posn) * (long)direction;
    printf("ret = %ld\n",ret);
    printf("posn = %s\n",posn);
    //Here I will active the stepper...
    return ret;
}

When I click the forward button, it is like the validate_position is executed twice, once forward and once reverse:
Code:
ret = 12
posn = 12
ret = -12
posn = 12

And nothing happens when I click Reverse.
Also I guess the last parameter of the g_signal_callback cannot be anything else than a pointer. There must be a better way to pass the -1 and 1 values...


Last edited by mariostg on Sun Jan 22, 2012 6:45 pm, edited 1 time in total.

Top
 Profile  
 
 Post subject: Re: g_signal_connect - Trying to understand.
PostPosted: Wed Jan 18, 2012 11:02 pm 
Offline
Familiar Face

Joined: Sun Jan 01, 2012 7:28 pm
Posts: 14
Location: Québec
Oups this is what happens when you copy and paste, I forgot to change (G_OBJECT(btn_forward)) to (G_OBJECT(btn_reverse)) in the reverse button.

Nonetheless, I still wonder about a better way to pass the last parameter??


Top
 Profile  
 
 Post subject: Re: g_signal_connect - Trying to understand.
PostPosted: Thu Jan 19, 2012 5:36 am 
Offline
GTK+ Geek

Joined: Fri Sep 04, 2009 6:53 am
Posts: 68
I would probably feel safer to use the GINT_TO_POINTER and GPOINTER_TO_INT macros instread of the direct cast (gpointer) and (long).

http://developer.gnome.org/glib/stable/ ... escription


Top
 Profile  
 
 Post subject: Re: g_signal_connect - Trying to understand.
PostPosted: Thu Jan 19, 2012 6:42 am 
Offline
Familiar Face

Joined: Thu Dec 15, 2011 6:23 pm
Posts: 36
Location: Hrvatska
asdfgh2091 answered just what you need.
Let me add one more thing. The callback function prototype for the CLICKED signal looks like this:
Code:
void        user_function       (GtkButton *button, gpointer   user_data) 

It brings you double check: button pointer and user_data. In your sample you use user_data. It is OK. You can also use widget name for this purpose:
Code:
gtk_widget_set_name (GTK_WIDGET(btn1), "1");
gtk_widget_set_name (GTK_WIDGET(btn2), "2");

and after that, in CALLBACK function you can check this:
Code:
if ( g_strcmp0 ( gtk_widget_get_name ( GTK_WIDGET(button)),"1")==0)
// button 1 clicked


Top
 Profile  
 
 Post subject: Re: g_signal_connect - Trying to understand.
PostPosted: Thu Jan 19, 2012 7:37 am 
Offline
Never Seen the Sunlight

Joined: Mon Apr 28, 2008 5:52 am
Posts: 799
Location: UK
Hi,

In the original posters message he had used g_signal_connect_swapped() so in this case his call-back function proto-type will look like
Code:
void        user_function       (gpointer   user_data, GtkButton *button)
He had just chosen to ignore the final argument.

Also I would recommend not to use gtk_widget_set_name() as its intended use is for themes and styling and could have some unfortunate side effects. It would be better to stay with passing the data through the "gpointer user_data". So if the data is the same size or smaller than a pointer and the value does not need to change then just cast it and it will be passed on to the call-back function. Else just pass a pointer to an allocated section of memory with the data to be passed onto the call-back function.

_________________
E.


Top
 Profile  
 
 Post subject: Re: g_signal_connect - Trying to understand.
PostPosted: Thu Jan 19, 2012 11:47 am 
Offline
Never Seen the Sunlight

Joined: Thu Mar 24, 2011 2:10 pm
Posts: 328
Location: Sydney, Australia
Additionally you would be better off using a spin button than a GTK_ENTRY. That way you don't have to worry about when users may accidentally input a non umeric character. Also setting it to have no decimal places (i.e. an integer) will make the program more transparent to the user e.g. they might enter 0.4 and wonder why it's not going anywhere.
Oh and check out glib for replacements for printf. If you're going to program in GTK you may as well make it platform independent.


Top
 Profile  
 
 Post subject: Re: g_signal_connect - Trying to understand.
PostPosted: Fri Jan 20, 2012 2:39 am 
Offline
Familiar Face

Joined: Sun Jan 01, 2012 7:28 pm
Posts: 14
Location: Québec
Wow, I am new here, and I must admit I am impressed by the replies.

@asdfgh2091
Thanks for "pointing" this out. I did not know such things existed. I will look into this further as soon as I decypher all that.

@kepica
I think you are loosing me here. I have to study more what you said. At the moment, my user_function as you call it, I assume you refer to validate_position return long for two reason. One, I could not figure out how to handle the type conversion (I actually wanted Int) and also because it "validates" something, well to me it has to return some success or failure. I am still trying to figure this out.

@errol
Ok... I am so confused. I used g_signal_connect_swapped() because I think I could not get it to work by using g_signal_connect(). I read the docs and so far some of Andrew Krause book and I have a hard time understanding the concept. I am roughly at chapter three...ish.
As a curiosity, that allocated section of memory you are refering too, can that be a function? The terminology "data" confuses me.

@Paul
Yeah, a spin button might be my next widget to play with. As far as it goes for multi-platform, that is not really my ambition at the moment.


Top
 Profile  
 
 Post subject: Re: g_signal_connect - Trying to understand.
PostPosted: Fri Jan 20, 2012 9:05 am 
Offline
Never Seen the Sunlight

Joined: Mon Apr 28, 2008 5:52 am
Posts: 799
Location: UK
The main loop for GTK http://developer.gnome.org/gtk3/stable/gtk3-General.html is based on the Glib main loop see http://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html. This is where the call-back functions will be called from on the many events that may happen such as the "clicked" on your button.

Each call-back function will have a particular way of being called, so the proto-type for the "clicked" signal for a GtkButton is
Code:
void user_function (GtkButton *button, gpointer   user_data)
Signal call-back functions can also be called with many arguments, for example the "move-cursor" signal for GtkTextView
Code:
void                user_function                      (GtkTextView    *text_view,
                                                        GtkMovementStep step,
                                                        gint            count,
                                                        gboolean        extend_selection,
                                                        gpointer        user_data)


You must follow the proto-types for each signal as it is in the documentation otherwise you may end up with very unexpected problems or crashes. Most signal call-back functions do not have a return value and if they do it is usually information for the GTK/Glib main loop mainly to say disconnect this signal or to carry on with other signal call-back functions or not.

The arguments passed to a call-back function will be any information relevant to that signal. So for the "clicked" for GtkWidget this is a pointer to the GtkButton the signal happened to. Then there is "gpointer user_data" this can be used for your own purposes and the value passed to the call-back functions is the value passed when you connected the signal. "user_data" can be an integer value if suitable cast. The way to do that is how "asdfgh2091" pointed out, doing it this way makes it very clear that what you are passing will be an integer and will do the casting properly for you. As it is a pointer it can point to anything, so it can pointer to a function, point to an area of data which could be anything such as an array of data or a structure.

Going back to your original call-back function for the "clicked" signal for GtkButton, you have done some things right and some things wrong.
- The value you have returned from the call-back will be ignored as the signal is expecting the call-back function not to return a value. You would be better to check for any errors, bounds checking or other things within the call-back function.

- You have used g_signal_connect_swapped() to connect your signal. This basically places the "user_data" as the first argument. In your case you have chosen to ignore the other arguments, which is OK, but for some people this can be seen as bad.

As Paul said in his post a GtkSpinButton http://developer.gnome.org/gtk3/stable/GtkSpinButton.html would be better for setting data for a stepper motor. This way you can set the input range (minimum and maximum values) have only integer values allowed have up/down buttons and have all this handled for you by GTK. All you have to do is handle the higher level stuff of getting when the value changes and setting your stepper motor.

Also it is worth reading on the Glib library functions so that you know what is there. Much of it is very useful with helper functions for data structures, string handling (ASCII and UTF8 including conversion to and from other formats), threads, and many other utility functions. I have seen too many people write the same bit of code of between 5 to 20 lines repeatedly some times in slightly different ways each time and with this code not being easy to read. This can often be replaced with a single function call which is easy to see what it does.

_________________
E.


Top
 Profile  
 
 Post subject: Re: g_signal_connect - Trying to understand.
PostPosted: Sat Jan 21, 2012 8:35 pm 
Offline
Familiar Face

Joined: Sun Jan 01, 2012 7:28 pm
Posts: 14
Location: Québec
I rewrote my signal connect functions as follow. User data is NULL
Code:
  btn_forward = gtk_button_new_with_mnemonic ("_Forward");
  g_signal_connect (G_OBJECT(btn_forward),"clicked",
          G_CALLBACK(validate_position), NULL);

  btn_reverse = gtk_button_new_with_mnemonic ("_Reverse");
  g_signal_connect (G_OBJECT(btn_reverse),"clicked",
          G_CALLBACK(validate_position), NULL);

Instead of dealing with user data, the validate_position function reads the button label.
Obviously, if that was a multilingual application or if it was an icon that would be a problem.
Anyone, feel free to comment on that aspect.
Anyway function goes like so which by the way now returns void. :)
Code:
void validate_position(GtkButton *button)
{
    const gchar* posn=gtk_entry_get_text(GTK_ENTRY (text_posn));
    const gchar* direction=gtk_button_get_label(GTK_BUTTON(button));
    gint ret;

    if (g_strcmp0(direction, (gpointer) "_Forward")==0)
    {
        //ret=GPOINTER_TO_INT(posn);
        ret=atoi(posn);
    }
    else if (g_strcmp0( direction, (gpointer) "_Reverse")==0)
    {
        ret=atoi(posn)*-1;
    }
    printf("ret = %d\n",GPOINTER_TO_INT(posn));
    //run_motor(ret);
}
static void enter_callback ( gpointer text_posn)
{
    const gchar *val;
    val=gtk_entry_get_text(GTK_ENTRY (text_posn));
    printf ("Entry content %s\n",val);
}

I did not implemented spin button yet. I want to understand the following first.
I tried to fiddle around with the GPOINTER_TO_INT macro as suggested, but obviously it is not the way it works I guess. My stepper went on for quite a long spin LOL.

The docs say
Quote:
GPOINTER_TO_INT. Extracts an integer from a pointer. The integer must have been stored in the pointer with GINT_TO_POINTER().

Does this mean that
Code:
const gchar* posn=gtk_entry_get_text(GTK_ENTRY (text_posn));
has to be stored as quoted?


Top
 Profile  
 
 Post subject: Re: g_signal_connect - Trying to understand.
PostPosted: Sat Jan 21, 2012 10:43 pm 
Offline
Never Seen the Sunlight

Joined: Mon Apr 28, 2008 5:52 am
Posts: 799
Location: UK
Yes you will have problems later if you decide to localise your application.

I would connect the signals this way, taking advantage of the user data to indicate which direction we are going.
Code:
  btn_forward = gtk_button_new_with_mnemonic ("_Forward");
  g_signal_connect (G_OBJECT(btn_forward),"clicked",
          G_CALLBACK(validate_position), GINT_TO_POINTER(1));

  btn_reverse = gtk_button_new_with_mnemonic ("_Reverse");
  g_signal_connect (G_OBJECT(btn_reverse),"clicked",
          G_CALLBACK(validate_position), GINT_TO_POINTER(-1));


Code:
void validate_position(GtkButton *button, gpointer user_data)
{
    const gchar *posn = gtk_entry_get_text(GTK_ENTRY (text_posn));
    gint direction = GPOINTER_TO_INT(user_data);
    gint ret = atoi(posn) * direction;

    printf("ret = %d\n", ret);
    //run_motor(ret);
}
static void enter_callback ( gpointer text_posn)
{
    const gchar *val;
    val=gtk_entry_get_text(GTK_ENTRY (text_posn));
    printf ("Entry content %s\n",val);
}


I am not sure about your function enter_callback(), but if it is for a signal then it does not look right. :-/
Note you should do some error checking on the text entry, as that could have anything entered into it including text and possibly overflow the integer, negative numbers and possibly return an unknown value. Think about using strtol() in the standard C library or g_ascii_strtoll() in Glib which have more error checking, so you know you have an error in the conversion, but you may want more checking else where.

_________________
E.


Top
 Profile  
 
 Post subject: Re: g_signal_connect - Trying to understand.
PostPosted: Sun Jan 22, 2012 2:01 am 
Offline
Familiar Face

Joined: Sun Jan 01, 2012 7:28 pm
Posts: 14
Location: Québec
Thanks errol. Now I get the principle of GINT_TO_POINTER ans its counterpart. Kind of interesting.

The enter_callback is an artifact. I did not even notice I copied it there. :)

I am in fact using strtol in the main of my stepper_main.c file to do some validation because I also run it from the command line or from a text file redirect. But I agree, doing some validation through the form is probably a good idea. It would be a good exercise anyway.

Thanks again.


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

All times are UTC


Who is online

Users browsing this forum: No registered users and 5 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