signal_connect 函数中的指针工作不正确
The pointer in signal_connect function is not working correct
我想使用 g_signal_connect()
函数更改特定 struct/class
中的数据。所以,在我看来,最好的方法是使用指向 struct
的指针。问题是指针的信息好像一直在变
我花了很多时间来弄清楚为什么会这样,但我不知道。
我可以毫无错误地编译和 运行 代码,但输出总是不同的。
以后想用几个event_box连接一个struct数组或者一个class数组(event_box[0]
连接data[0]
,... ).
我希望有人明白我的意思,我很乐意提供任何帮助。
#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;
}
如果我多次单击该框,输出:
status = 4
ID = 32193184
status = 5
ID = 32193184
status = 4
ID = 32193184
status = 6
ID = 32193184
status = 4
ID = 32193184
I hope someone understands what I mean and I would be happy about any
help.
好吧,是的.. 你为 button-press-event
使用了错误的函数原型。 button-press-event
的原型是:
The “button-press-event” signal
gboolean
user_function (GtkWidget *widget,
GdkEvent *event,
gpointer user_data)
(注意: 信号是正确的 "button-press-event"
而不是 "button_press_event"
,尽管有一个 #define
允许第二种形式工作)
参见 GtkWidget (Gtk+3 Manual)。所以你的函数应该是这样的:
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;
}
额外尼特
使用g_print
代替printf
,使用gboolean
代替bool
。虽然传递 address of
适用于小型结构,但对于大型结构,您应该使用 g_slice_new
.
进行分配
我将在@David C. Rankin 说的这部分稍微扩展一下:
(void)wid; /* cast to void to avoid unused var warning */
(void)event;
因为有很多人不知道的重要事情。
cast 的需要一直被错误使用,这是因为还有另一个函数被调用:
g_signal_connect_swapped()
通过将第一个参数与最后一个参数交换来避免这么多转换的需要。
举个例子:
#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();
}
在这里你可以看到回调函数签名如下所示:
void user_function ( GtkWidget *object, gpointer user_data )
现在在这种情况下需要两个转换,但我们可以通过调用 g_signal_connect_swapped
来删除其中一个(例如 gpointer 数据):
g_signal_connect_swapped ( window, "destroy", G_CALLBACK( user_function ), NULL
甚至更好:
g_signal_connect_swapped ( window, "destroy", G_CALLBACK( user_function ), (gpointer)"Goodbye" );
现在我们的程序是这样的:
#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();
}
而且已经没有 CAST 了。
这是一个更好的例子:
#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;
}
我想使用 g_signal_connect()
函数更改特定 struct/class
中的数据。所以,在我看来,最好的方法是使用指向 struct
的指针。问题是指针的信息好像一直在变
我花了很多时间来弄清楚为什么会这样,但我不知道。 我可以毫无错误地编译和 运行 代码,但输出总是不同的。
以后想用几个event_box连接一个struct数组或者一个class数组(event_box[0]
连接data[0]
,... ).
我希望有人明白我的意思,我很乐意提供任何帮助。
#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;
}
如果我多次单击该框,输出:
status = 4
ID = 32193184
status = 5
ID = 32193184
status = 4
ID = 32193184
status = 6
ID = 32193184
status = 4
ID = 32193184
I hope someone understands what I mean and I would be happy about any help.
好吧,是的.. 你为 button-press-event
使用了错误的函数原型。 button-press-event
的原型是:
The “button-press-event” signal
gboolean
user_function (GtkWidget *widget,
GdkEvent *event,
gpointer user_data)
(注意: 信号是正确的 "button-press-event"
而不是 "button_press_event"
,尽管有一个 #define
允许第二种形式工作)
参见 GtkWidget (Gtk+3 Manual)。所以你的函数应该是这样的:
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;
}
额外尼特
使用g_print
代替printf
,使用gboolean
代替bool
。虽然传递 address of
适用于小型结构,但对于大型结构,您应该使用 g_slice_new
.
我将在@David C. Rankin 说的这部分稍微扩展一下:
(void)wid; /* cast to void to avoid unused var warning */
(void)event;
因为有很多人不知道的重要事情。
cast 的需要一直被错误使用,这是因为还有另一个函数被调用:
g_signal_connect_swapped()
通过将第一个参数与最后一个参数交换来避免这么多转换的需要。
举个例子:
#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();
}
在这里你可以看到回调函数签名如下所示:
void user_function ( GtkWidget *object, gpointer user_data )
现在在这种情况下需要两个转换,但我们可以通过调用 g_signal_connect_swapped
来删除其中一个(例如 gpointer 数据):
g_signal_connect_swapped ( window, "destroy", G_CALLBACK( user_function ), NULL
甚至更好:
g_signal_connect_swapped ( window, "destroy", G_CALLBACK( user_function ), (gpointer)"Goodbye" );
现在我们的程序是这样的:
#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();
}
而且已经没有 CAST 了。
这是一个更好的例子:
#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;
}