Reputation: 13
I want to use the g_signal_connect()
function to change data in a specific struct/class
. So, in my opinion, the best way is to use a pointer to the struct
. the problem is that the information of the pointer seems to be changing all the time.
I spent a lot of time to figure out why is that happening, but I have no idea. I can compile and run the code without any error but the output is always different.
Later I want to use several event_box to connect to an array of struct or an array of a class (event_box[0]
connect to data[0]
,...).
I hope someone understands what I mean and I would be happy about any help.
#include<gtk/gtk.h>
struct d
{
bool status;
int ID;
};
void end_program(GtkWidget *wid, gpointer ptr)
{
gtk_main_quit();
}
void box_click(GtkWidget *wid, gpointer user_data)
{
struct d *data = (struct d*)user_data;
printf("status = %i\n", data->status);
printf("ID = %i\n", data->ID);
}
int main (int argc, char *argv[])
{
struct d data;
data.status = 0;
data.ID = 1;
gtk_init(&argc, &argv);
GtkWidget *win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
GtkWidget *event_box = gtk_event_box_new();
g_signal_connect(G_OBJECT(event_box), "button_press_event", G_CALLBACK(box_click), &data);
gtk_container_add(GTK_CONTAINER(win), event_box);
gtk_widget_show_all(win);
g_signal_connect(win, "delete_event", G_CALLBACK(end_program),NULL);
gtk_main();
return 0;
}
Output if I click the box several times:
status = 4
ID = 32193184
status = 5
ID = 32193184
status = 4
ID = 32193184
status = 6
ID = 32193184
status = 4
ID = 32193184
Upvotes: 1
Views: 619
Reputation: 5307
I will extend a little bit this part where @David C. Rankin said:
(void)wid; /* cast to void to avoid unused var warning */
(void)event;
Because there is something important which a lot o people does not know about it.
The need of cast is all most all the time wrong used, and this happens because there is another function which is called:
g_signal_connect_swapped()
Which is there to avoid the need of so many casts by swapping the fist parameter with the last one.
Lets take the following example:
#include <gtk/gtk.h>
GtkWidget *createWindow ( const gint width, const gint height );
void user_function ( GtkWidget *object, gpointer user_data );
int main ( void )
{
GtkWidget *window;
gtk_init ( NULL, NULL );
/// ***
window = createWindow( 300, 300 );
/// ***
g_signal_connect ( window, "destroy", G_CALLBACK( user_function ), NULL );
/// ***
gtk_widget_show_all ( window );
gtk_main();
}
GtkWidget *createWindow ( const gint width, const gint height )
{
GtkWidget *window = gtk_window_new ( GTK_WINDOW_TOPLEVEL );
gtk_widget_set_size_request ( window, width, height );
gtk_container_set_border_width ( GTK_CONTAINER ( window ), 50 );
return window;
}
void user_function ( GtkWidget *object, gpointer user_data )
{
(void)object;
(void)user_data;
g_print( "Goodbye\n" );
gtk_main_quit();
}
Here as you can see the callback function signature looks like this:
void user_function ( GtkWidget *object, gpointer user_data )
Now there are two casts needed in this case, but we can drop one (gpointer data for example) of them by calling g_signal_connect_swapped
like this:
g_signal_connect_swapped ( window, "destroy", G_CALLBACK( user_function ), NULL
or even better:
g_signal_connect_swapped ( window, "destroy", G_CALLBACK( user_function ), (gpointer)"Goodbye" );
Now our program looks like this:
#include <gtk/gtk.h>
GtkWidget *createWindow ( const gint width, const gint height );
void user_function ( gpointer data );
int main ( void )
{
GtkWidget *window;
gtk_init ( NULL, NULL );
/// ***
window = createWindow( 300, 300 );
/// ***
g_signal_connect_swapped ( window, "destroy", G_CALLBACK( user_function ), (gpointer)"Goodbye" );
/// ***
gtk_widget_show_all ( window );
gtk_main();
}
GtkWidget *createWindow ( const gint width, const gint height )
{
GtkWidget *window = gtk_window_new ( GTK_WINDOW_TOPLEVEL );
gtk_widget_set_size_request ( window, width, height );
gtk_container_set_border_width ( GTK_CONTAINER ( window ), 50 );
return window;
}
void user_function ( gpointer data )
{
g_print( "%s\n", (char*)data );
gtk_main_quit();
}
And there are no CASTs anymore.
Here is a better Example:
#include <gtk/gtk.h>
gboolean scroll_callback ( GtkWidget *widget, GdkEvent *event );
gboolean show_mouse_pressed ( GtkWidget *widget, GdkEventButton *event );
int main ( void )
{
GtkWidget *window;
GtkWidget *button;
gtk_init( NULL, NULL );
/// ***
window = gtk_window_new( GTK_WINDOW_TOPLEVEL );
gtk_window_set_default_size( GTK_WINDOW( window ), 300, 250 );
g_signal_connect( window, "destroy", gtk_main_quit, NULL );
gtk_container_set_border_width( GTK_CONTAINER( window ), 50 );
/// ***
button = gtk_button_new_with_mnemonic( "_Click me" );
gtk_widget_add_events( button, GDK_BUTTON_PRESS );
gtk_widget_add_events( button, GDK_SCROLL_MASK );
///g_signal_connect( button, "clicked", gtk_main_quit, NULL );
gtk_container_add( GTK_CONTAINER( window ), button );
/// ***
g_signal_connect_swapped( button, "button_press_event", G_CALLBACK( show_mouse_pressed ), window );
g_signal_connect_swapped( button, "scroll_event", G_CALLBACK( scroll_callback ), window );
/// ***
gtk_widget_show_all( window );
gtk_main();
}
gboolean scroll_callback ( GtkWidget *widget, GdkEvent *event )
{
if ( event->type == GDK_SCROLL ) /// Scroll was Catched ?
{
if ( event->scroll.direction == GDK_SCROLL_DOWN ) /// It is down?
{
g_print( "Scroll-Down Detected\n" );
gtk_window_set_title( GTK_WINDOW( widget ), "Scroll-Down Detected" );
}
if ( event->scroll.direction == GDK_SCROLL_UP ) /// It is up?
{
g_print( "Scroll-UP Detected\n" );
gtk_window_set_title( GTK_WINDOW( widget ), "Scroll-UP Detected" );
}
return FALSE;
}
return TRUE;
}
gboolean show_mouse_pressed ( GtkWidget *widget, GdkEventButton *event )
{
assert ( widget != NULL );
if ( gtk_widget_get_has_window ( widget ) )
{
if ( event->type == GDK_BUTTON_PRESS )
{
g_print( "The mouse clicked the button\n" );
gtk_window_set_title( GTK_WINDOW( widget ), "The mouse was Clicked" );
}
return TRUE;
}
return FALSE;
}
Upvotes: 0
Reputation: 84632
I hope someone understands what I mean and I would be happy about any help.
Well, yes.. You are using the wrong function prototype for a button-press-event
. The prototype for a button-press-event
is:
The “button-press-event” signal
gboolean
user_function (GtkWidget *widget,
GdkEvent *event,
gpointer user_data)
(note: the signal is properly "button-press-event"
instead of "button_press_event"
, though there is a #define
allowing the second form to work)
See GtkWidget (Gtk+3 Manual). So what your function should look like is:
gboolean box_click(GtkWidget *wid, GdkEvent *event, gpointer user_data)
{
struct d *data = user_data; /* no need for cast, gpointer is void* */
g_print("status = %d\n", data->status);
g_print("ID = %d\n", data->ID);
return TRUE; /* to prevent further handling, FALSE otherwise */
(void)wid; /* cast to void to avoid unused var warning */
(void)event;
}
Additional Nits
Use g_print
instead of printf
, use gboolean
instead of bool
. While passing the address of
is fine for small structs, for large structs you should allocate with g_slice_new
.
Upvotes: 3