C 信号连接功能中的指针工作不正常

C 信号连接功能中的指针工作不正常,c,pointers,gtk3,gtkmm,C,Pointers,Gtk3,Gtkmm,我想使用g\u signal\u connect()函数更改特定struct/class中的数据。因此,在我看来,最好的方法是使用指向struct的指针。问题是指针的信息似乎一直在变化 我花了很多时间想弄明白为什么会这样,但我不知道。 我可以编译和运行代码,没有任何错误,但输出总是不同的 稍后我想使用几个事件框连接到结构数组或类数组(event\u框[0]connect todata[0],…) 我希望有人理解我的意思,我会很高兴得到任何帮助 #include<gtk/gtk.h>

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

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

稍后我想使用几个事件框连接到结构数组或类数组(
event\u框[0]
connect to
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;
}
我希望有人能理解我的意思,我也会很高兴 救命啊

嗯,是的。。您对按钮按下事件使用了错误的函数原型。按钮按下事件的原型是:

The “button-press-event” signal

gboolean
user_function (GtkWidget *widget,
               GdkEvent  *event,
               gpointer   user_data)
注意:信号正确地显示为“按钮按下事件”,而不是“按钮按下事件”,尽管有一个
\define
允许第二个表单工作)

看。因此,您的函数应该是:

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;
}
附加NIT


使用
g_print
代替
printf
,使用
gboolean
代替
bool
。传递
地址对于小型结构很好,但是对于大型结构,您应该使用
g_slice\u new
进行分配。我将对这一部分进行一点扩展,其中@David C.Rankin说:

(void)wid;      /* cast to void to avoid unused var warning */
(void)event;
因为有些重要的事情很多人都不知道

cast的需求一直都是错误的,这是因为有另一个函数被调用:

g_signal_connect_swapped()
通过将fist参数与最后一个参数交换,可以避免进行如此多的强制转换

让我们以下面的例子为例:

#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();
}
或者更好:

g_signal_connect_swapped ( window, "destroy", G_CALLBACK( user_function ),  (gpointer)"Goodbye" );
现在我们的程序如下所示:

g_signal_connect_swapped ( window, "destroy", G_CALLBACK( user_function ),  NULL 
#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();
}
#包括
GtkWidget*createWindow(常量基特宽度、常量基特高度);
无效用户_函数(gpointer数据);
内部主(空)
{
GtkWidget*窗口;
gtk_init(NULL,NULL);
/// ***
window=createWindow(300300);
/// ***
g_信号连接交换(窗口,“销毁”,g_回调(用户函数),(gpointer)“再见”);
/// ***
gtk_小部件_全部显示(窗口);
gtk_main();
}
GtkWidget*createWindow(常量基特宽度、常量基特高度)
{
GtkWidget*window=gtk_window_new(gtk_window_TOPLEVEL);
gtk_小部件_设置_大小_请求(窗口、宽度、高度);
gtk_容器设置_边框宽度(gtk_容器(窗口),50);
返回窗口;
}
无效用户_函数(gpointer数据)
{
g_print(“%s\n”,(char*)数据);
gtk_main_quit();
}
再也没有石膏了

下面是一个更好的例子:

#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;
}
#包括
gboolean scroll_回调(GtkWidget*小部件,GdkEvent*事件);
gboolean show_mouse_pressed(GtkWidget*小部件,GdkEventButton*事件);
内部主(空)
{
GtkWidget*窗口;
GtkWidget*按钮;
gtk_init(NULL,NULL);
/// ***
窗口=gtk_窗口_新建(gtk_窗口_顶层);
gtk_窗口设置默认大小(gtk_窗口(窗口),300250);
g_信号连接(窗口,“销毁”,gtk_主退出,空);
gtk_容器设置_边框宽度(gtk_容器(窗口),50);
/// ***
button=gtk_button_new_,带助记符(“_ClickMe”);
gtk_小部件_添加_事件(按钮、GDK_按钮_按下);
gtk_小部件_添加_事件(按钮、GDK_滚动_掩码);
///g_信号连接(按钮“点击”,gtk_主退出,空);
gtk_容器添加(gtk_容器(窗口),按钮);
/// ***
g_信号连接交换(按钮,“按钮按下事件”,g_回调(显示鼠标按下),窗口);
g_信号连接交换(按钮,“滚动事件”,g_回调(滚动回调),窗口);
/// ***
gtk_小部件_全部显示(窗口);
gtk_main();
}
gboolean scroll_回调(GtkWidget*小部件,GdkEvent*事件)
{
如果(事件->类型==GDK\u滚动)///滚动被捕获?
{
如果(event->scroll.direction==GDK\u scroll\u DOWN)///它是向下的吗?
{
g_打印(“检测到向下滚动\n”);
gtk_窗口_设置_标题(gtk_窗口(小部件),“检测到向下滚动”);
}
如果(event->scroll.direction==GDK\u scroll\u UP)///它是向上的吗?
{
g_打印(“检测到向上滚动\n”);
gtk_窗口设置标题(gtk_窗口(小部件),“检测到向上滚动”);
}
返回FALSE;
}
返回TRUE;
}
gboolean显示鼠标按下(GtkWidget*小部件,GdkEventButton*事件)
{
断言(小部件!=NULL);
如果(gtk_小部件_获取_有_窗口(小部件))
{
如果(事件->类型==GDK\u按钮\u按下)
{
g_print(“鼠标点击按钮”);
gtk_窗口_设置_标题(gtk_窗口(小部件),“点击鼠标”);
}
返回TRUE;
}
返回FALSE;
}

谢谢!到目前为止,这对我很有效。我只是不明白为什么我必须使用
struct d*data=(struct d*)user\u data
而不是
struct d*data=user\u data
。如果我尝试在没有
(struct d*)
的情况下使用它,我会得到以下错误:
main.cpp:在函数“gboolean box”中单击(GtkWidget*,GdkEvent*,gpointer)∶main.cpp:16:22:错误:从“gpointer{aka void*}”到“d*”[-fppermissive]struct d*data=user\u数据的转换无效哦,如果你正在用C++编译,那么你需要的是<代码>(StuttD*) Case.GTK通常用C编译,GTKMM是C++。(这也解释了为什么你用
bool
而不是
gboolean
)。谁让你在Gtk中使用
.cpp
的?好的,我明白了。没有人告诉我使用.CPP我只是使用它,因为在我开始GTK之前,我总是用C++编写我的程序。我开始学习lea
#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;
}