我如何组织 GTK 程序?
How do i organize a GTK program?
我有一个名为 create_interface
的函数。在该函数中是打开菜单按钮的信号处理程序(菜单是在 create_interface
中创建的)。我想传递 window 小部件并传递树视图小部件,因为当您打开文件时,树视图中的条目应该显示出来。我尝试将它们作为结构传递,但是,尽管它有效,但 GTK 生成了一些错误消息。
// This is global.
struct everything
{
GtkWidget *window;
GtkWidget *tree_view;
}
GtkWidget *create_interface (void)
{
struct everything instance;
struct everything *widgets;
widgets = &instance;
...code here...
g_signal_connect(file_mi_open_file_dialog, "clicked", G_CALLBACK(open_file_dialog), widgets);
函数 open_file_dialog
如下所示:
void open_file_dialog (GtkWidget *wid, gpointer data)
{
struct everything *sample_name = data;
...rest of code here...
我想知道是否有另一种组织程序的方法,这样您就不必拥有全局变量。
I tried passing them as a struct, but, although its works, GTK generates some error messages.
问题是您正在尝试使用堆栈分配的结构,它在 create_interface()
函数完成后变得无效,而您通常希望这些值在以后仍然有效及时(例如,当调用 open_file_dialog()
时。
I was wondering if there was another way of organizing a program so you do not have to have global variables.
一个可能的解决方案确实是使用一个全局变量:这在程序的整个生命周期中都是有效的,但它有一个主要的缺点:如果你必须为每个回调都这样做,它就无法扩展,而且它是建筑上不是很干净。
另一种解决方案是在堆上分配您的“闭包”(即您在创建回调时要捕获的变量),并在完成后释放它。如果您将字段保存在 GObject 中,GLib 甚至可以通过调用 g_signal_connect_data()
(or g_signal_connect_object()
来帮助您)
// Technically you don't need the typedef
typedef struct _ClickedClosure {
GtkWidget *window;
GtkWidget *treeview;
} ClickedClosure;
GtkWidget *create_interface (void)
{
// Note that the g_new0 allocates on the heap instead of using the stack
ClickedClosure *closure = g_new0 (ClickedClosure, 1);
// code here to initialize your window/treeview ...
// put the widgets in the closure
closure->window = my_window;
closure->treeview = treeview;
// Connect to the signal
g_signal_connect_data(file_mi_open_file_dialog, "clicked",
G_CALLBACK(open_file_dialog), closure, g_free, 0);
}
void open_file_dialog (GtkWidget *wid, gpointer data)
{
// Since this was allocated on the heap, this is still valid
ClickedClosure *sample_name = data;
// code handling here ...
}
很多时候,使用 GTK 的开发人员所做的是,他们已经在使用自己的 GObject classes/objects,然后他们可以将其与 g_signal_connect_object()
一起使用,或者通过 [= 手动释放它16=] 之后。然后使用 GObject 还允许您进行运行时类型检查转换,以确保您的闭包具有正确的类型。
我有一个名为 create_interface
的函数。在该函数中是打开菜单按钮的信号处理程序(菜单是在 create_interface
中创建的)。我想传递 window 小部件并传递树视图小部件,因为当您打开文件时,树视图中的条目应该显示出来。我尝试将它们作为结构传递,但是,尽管它有效,但 GTK 生成了一些错误消息。
// This is global.
struct everything
{
GtkWidget *window;
GtkWidget *tree_view;
}
GtkWidget *create_interface (void)
{
struct everything instance;
struct everything *widgets;
widgets = &instance;
...code here...
g_signal_connect(file_mi_open_file_dialog, "clicked", G_CALLBACK(open_file_dialog), widgets);
函数 open_file_dialog
如下所示:
void open_file_dialog (GtkWidget *wid, gpointer data)
{
struct everything *sample_name = data;
...rest of code here...
我想知道是否有另一种组织程序的方法,这样您就不必拥有全局变量。
I tried passing them as a struct, but, although its works, GTK generates some error messages.
问题是您正在尝试使用堆栈分配的结构,它在 create_interface()
函数完成后变得无效,而您通常希望这些值在以后仍然有效及时(例如,当调用 open_file_dialog()
时。
I was wondering if there was another way of organizing a program so you do not have to have global variables.
一个可能的解决方案确实是使用一个全局变量:这在程序的整个生命周期中都是有效的,但它有一个主要的缺点:如果你必须为每个回调都这样做,它就无法扩展,而且它是建筑上不是很干净。
另一种解决方案是在堆上分配您的“闭包”(即您在创建回调时要捕获的变量),并在完成后释放它。如果您将字段保存在 GObject 中,GLib 甚至可以通过调用 g_signal_connect_data()
(or g_signal_connect_object()
来帮助您)
// Technically you don't need the typedef
typedef struct _ClickedClosure {
GtkWidget *window;
GtkWidget *treeview;
} ClickedClosure;
GtkWidget *create_interface (void)
{
// Note that the g_new0 allocates on the heap instead of using the stack
ClickedClosure *closure = g_new0 (ClickedClosure, 1);
// code here to initialize your window/treeview ...
// put the widgets in the closure
closure->window = my_window;
closure->treeview = treeview;
// Connect to the signal
g_signal_connect_data(file_mi_open_file_dialog, "clicked",
G_CALLBACK(open_file_dialog), closure, g_free, 0);
}
void open_file_dialog (GtkWidget *wid, gpointer data)
{
// Since this was allocated on the heap, this is still valid
ClickedClosure *sample_name = data;
// code handling here ...
}
很多时候,使用 GTK 的开发人员所做的是,他们已经在使用自己的 GObject classes/objects,然后他们可以将其与 g_signal_connect_object()
一起使用,或者通过 [= 手动释放它16=] 之后。然后使用 GObject 还允许您进行运行时类型检查转换,以确保您的闭包具有正确的类型。