GTK / C在函数之间共享数据和变量

时间:2014-10-01 19:57:09

标签: c callback gtk global data-sharing

问题是:什么是在功能之间共享数据的最佳方式,特别是在GTK / C应用程序中?最好的意味着最合适的,最快的运行和/或吸收尽可能低的CPU功率。
我问,因为我必须在linux下使用GUI编写一些应用程序,但我更像是一个微控制器程序员(也许我很难像大型计算机一样思考)。在小型8位MCU的世界中,代码是普通的C,全局变量是在函数之间共享数据的最快和最常用的方式。
但我想,在操作系统下运行的更复杂的应用程序中,必须有其他特殊的应用程序。这样做的方法。到目前为止,我注意到GTK(GDK,Glib等)提供了许多特殊的功能和内置机制,使程序员的生活变得最简单,所以我认为它应该是在函数之间共享变量的优雅。 通过网络搜索,我看到了不同的解决方案:
- 带有私有变量的类和获取/设置它们的方法 - 但我的应用程序是用C编写的,而不是C ++,我想避免使用对象编程,
- 全球结构甚至是一个拥有许多成员的大型全球结构,
- 良好的普通全球,
- GtkClipboard,但我认为它用于不同的目的。

我想要做的只是设置一些变量' A'在一个回调函数中,在第二个回调中再次设置该变量,然后在另一个回调中做一些取决于变量' A'的值,如下所示:

callback_func1{
//...
A = some_func();
//...
}
callback_func2{
//...
A = another_func();
//...
}
callback_func3{
//...
if(A>threshold) do_something();
else do_nothing();
//...
}

2 个答案:

答案 0 :(得分:2)

你应该对全局变量保持警惕,特别是如果你只想让某些函数修改它们的话。

假设您保留的数据不仅仅是A(为简单起见,我将其定义为int),您可以用熟悉的方式设置结构

typedef struct t_MYCBSD
{
    int A;
    // other members
} MYCBSD; // callback struct data

根据需要包括其他数据成员。 (我已经包含了t_MYCBSD,以防有一些自我引用)。

然后,您可以按如下方式实现回调函数:

void callback_func1( GtkWidget *widget, gpointer user_data )
{
    MYCBSD *data = user_data;
    data->A = some_func();
}

void callback_func2( GtkWidget *widget, gpointer user_data )
{
    MYCBSD *data = user_data;
    data->A = another_func();
}

void callback_func3( GtkWidget *widget, gpointer user_data )
{
    MYCBSD *data = user_data;

    if( data->A > threshold ) do_something();
    else do_nothing();
}

显然,some_func()another_func()thresholddo_something()do_nothing()在此上下文中有效。

注意:指向结构的data指针使语法更加清晰。您也可以使用:

((MYCBSD *) user_data)->A = some_func();

无论如何,您通常在创建小部件时设置回调。在下面(严重淘汰的非GtkBuilder)代码中,MYCBSD mydata将是本地范围的。我假设将为某些按钮设置回调,并点击"点击"事件

int main( int argc, char* argv[] )
{
    MYCBSD mydata;
    // Below-referenced widgets
    GtkWidget *mywidget1, *mywidget2, *mywidget3;
    // ... other widgets and variables

    mydata.A = 0;   // Optionally set an initial value to A

    // Standard init via gtk_init( &argc, &argv );

    // ... Create the toplevel and a container of some kind

    // Create mywidget1,2,3 (as buttons, for example)
    mywidget1 = gtk_button_new_with_label ("widget1");
    mywidget2 = gtk_button_new_with_label ("widget2");
    mywidget1 = gtk_button_new_with_label ("widget3");

    g_signal_connect( mywidget1, "clicked", G_CALLBACK(callback_func1), &mydata );
    g_signal_connect( mywidget2, "clicked", G_CALLBACK(callback_func2), &mydata );
    g_signal_connect( mywidget3, "clicked", G_CALLBACK(callback_func3), &mydata );

    // ... Attach those widgets to container
    // ... and show all

    // Run the app in a standard way via gtk_main();

    return 0;
}

这里的重要部分是:

    g_signal_connect( mywidget1, "clicked", G_CALLBACK(callback_func1), &mydata );
    g_signal_connect( mywidget2, "clicked", G_CALLBACK(callback_func2), &mydata );
    g_signal_connect( mywidget3, "clicked", G_CALLBACK(callback_func3), &mydata );

最后一个参数将数据传递给回调函数。

如果您只想共享一个值A,则可以在不需要结构的情况下以类似方式传递该值。

答案 1 :(得分:0)

如果你想使用全局变量,只需使用全局变量。并且,无论世界上说什么,没有人因为使用全球化而死亡。

避免使用全局,因为对大型程序进行维护很难,而且从您的描述来看,情况似乎并非如此。

在共享方面,GTK +程序通常不是并行的,因此您可以毫无问题地自由访问RW中的全局变量。而且当使用任务时,最好将所有GTK +调用放在同一个任务上:你仍然可以从同一个任务中访问RW中的全局变量。