signal_connect函数中的指针无法正常工作

时间:2019-06-15 12:03:01

标签: c pointers gtk3 gtkmm

我想使用g_signal_connect()函数来更改特定struct/class中的数据。因此,我认为最好的方法是使用指向struct的指针。问题是指针的信息似乎一直在变化。

我花了很多时间弄清楚为什么会这样,但是我不知道。 我可以编译并运行代码而没有任何错误,但是输出总是不同的。

稍后,我想使用多个event_box连接到struct数组或类数组({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

2 个答案:

答案 0 :(得分:1)

  

我希望有人能理解我的意思,我会为任何事情感到高兴   帮助。

嗯,是的。您正在为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

答案 1 :(得分:0)

我将在@David C. Rankin说过的那部分进行扩展:

IsHidden= true;

onSelect(){
this.IsHidden=true;
 this.IsHidden= !this.IsHidden;
}

因为有些重要的东西很多人都不知道。

大多数时候,错误地使用了强制转换,这是因为还有另一个函数被称为:

(void)wid;      /* cast to void to avoid unused var warning */
(void)event;

在那里可以通过将fist参数与最后一个参数交换来避免大量的转换。

让我们举一个例子:

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

甚至更好:

g_signal_connect_swapped ( window, "destroy", G_CALLBACK( user_function ),  NULL 

现在我们的程序如下:

g_signal_connect_swapped ( window, "destroy", G_CALLBACK( user_function ),  (gpointer)"Goodbye" );

并且不再有CAST。

这是一个更好的例子:

#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();
}