GTK+ 2.0 教学-Hello World 详解

现在我们知道基本理论了,让我们来详细分析helloworld范例程式。

这是按钮被点击时要呼叫的回呼函式。在这个范例中我们忽略了参数 widget 和 data,但是使用这些参数也不难。下一个范例会使用 data 参数来告诉我们哪个按钮被按下了。

static void hello( GtkWidget *widget,
                   gpointer   data )
{
    g_print ("Hello World\n");
}

接下来的一个回呼函式有点特殊。”delete_event” 在视窗管理员发送这个事件给应用程式时发生。我们在这里可以选择对这些事件做什么。可以忽略它们,可以做一点回应,或是简单地退出程式。
这个回呼函式传回的值让 GTK 知道该如何去做。传回 TRUE,让它知道我们不想让 “destroy” 信号被发出,保持程式继续执行。传回 FALSE,我们让 “destroy” 信号发出,这接着会呼叫 “destroy” 信号处理函式。

static gboolean delete_event( GtkWidget *widget,
                              GdkEvent  *event,
                              gpointer   data )
{
    g_print ("delete event occurred\n");

    return TRUE;
}

这里是另一个回呼函式,它通过呼叫 gtk_main_quit() 来退出程式。这个函式告诉 GTK 当控制权返回给它时就从 gtk_main 退出。

static void destroy( GtkWidget *widget,
                     gpointer   data )
{
    gtk_main_quit ();
}

我假设你知道 main() 函式…是的,像其它程式一样,所有的 GTK 程式有一个 main() 函式。

int main( int   argc,
          char *argv[] )
{

接下来宣告两个指向 GtkWidget 型别的结构指标。它们被用于建构一个视窗和一个按钮。

GtkWidget *window;
GtkWidget *button;

这里又是 gtk_init()。跟前面一样,这个初始化工具包,分析命令列里的参数。它从参数列表中删除任何可以识别的参数,并且修改 argc 和 argv,使这些被删除的参数好像从来就不存在一样,而允许你的程式分析剩余的参数。

gtk_init (&argc, &argv);

建构一个新视窗,这个很容易。它为 GtkWidget *window 结构分配了记忆体,这样 window 现在指向了一个有效的结构。它建立了一个新视窗,但是这个视窗直到在程式后面部分我们呼叫 gtk_widget_show(window) 后才会显示出来。

window = gtk_window_new (GTK_WINDOW_TOPLEVEL);

这有两个连接一个信号处理器到一个物件 (本例中,就是 window ) 的范例。这里,”delete_event” 和 “destroy” 信号被捕获。当我们用视窗管理员去关闭视窗或呼叫函式 gtk_widget_destroy() 并将 window 元件作为物件传给它来销毁时,”delete_event” 信号发出。当我们在 “delete_event” 信号处理器中传回 FALSE 值时,”destroy” 信号发出。G_CALLBACK 是巨集,可以为我们执行型别转换和检测,同时也增加了程式码的可读性。(注:旧版有G_OBJECT已不在范例中使用)

g_signal_connect (window, "delete-event",
                      G_CALLBACK (delete_event), NULL);
g_signal_connect (window, "destroy",
                      G_CALLBACK (destroy), NULL);

接下来这个函式用于设置容器物件的属性。设置视窗边框宽度为10个像素。在设置元件的属性这一章还有其它类似函式。

再次,GTK_CONTAINER也是一个执行型别转换的巨集。

gtk_container_set_border_width (GTK_CONTAINER (window), 10);

这个呼叫建构一个新按钮。在记忆体中分配空间给一个新的 GtkWidget 结构,初始化它,并使 button 指标指向它。它显示后上面会有个 “Hello World” 标签。

button = gtk_button_new_with_label ("Hello World");

在 这,我们让这个按钮做一些有用的事。我们给按钮设置信号处理器,因此当按钮发出 “clicked” 信号时,hello() 函式被呼叫。我们忽略了 data 参数,简单地传送 NULL 给 hello() 回呼函式。很明显地,当我们用滑鼠点击按钮时,信号 “clicked” 被发出。

g_signal_connect (button, "clicked",
                      G_CALLBACK (hello), NULL);
注:下面程式码为旧版
g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (hello), NULL);

我 们也要使用这个按钮退出程式。这将说明 “destroy” 信号怎样由视窗管理员引发,或由我们的程式引发。当按钮被点击(“clicked”)时,和上面一样,它首先呼叫会 hello() 回呼函式,然后是这个函式,这依赖于它们被设置连接的顺序。你可以拥有许多回呼函式,所有的回呼按你设置连接的顺序依次执行。因为 gtk_widget_destroy() 函式只接受 GtkWidget *widget 作为唯一的参数,我们这里用 g_signal_connect_swapped() 函式而不直接使用 g_signal_connect()。

g_signal_connect_swapped (button, "clicked",
                              G_CALLBACK (gtk_widget_destroy),
                              window);
注:下面程式码为旧版
g_signal_connect_swapped (G_OBJECT (button), "clicked", G_CALLBACK (gtk_widget_destroy), G_OBJECT (window));

这是一个封装呼叫,在封装元件这一章将作深入讲解。不过它相当容易理解。它简单地告诉 GTK 要把按钮放在它显示的视窗里。注意一个 GTK 容器只能包含一个元件。还有其它的元件,在后面介绍,设计为用来以各种方法布置多个元件。

gtk_container_add (GTK_CONTAINER (window), button);

一切准备就绪。所有信号处理器连接好了,按钮也放进了视窗,我们让 GTK 在荧幕上“显示”这些元件。视窗元件最后显示,这样整个视窗会一下弹出,而不是先见到视窗弹出后再见到按钮。虽然这个简单的范例中,你不会注意到。

gtk_widget_show (button);

gtk_widget_show (window);

接着,当然,我们呼叫 gtk_main() 函式来等待来自 X 伺服器的事件,当这些事件到来时,呼叫元件发出信号。

gtk_main ();

最后传回,呼叫函式gtk_main_quit() 后控制权传回到这里。

return 0;

现在,当我们用滑鼠点击一个 GTK 按钮,元件发出一个 “clicked” 信号。为了让我们利用这个资讯,程式设置了一个信号处理器来捕获那个信号,它按我们的选择依次呼叫函式。在我们的范例中,当按下按钮时,以 NULL 作为参数呼叫函式 hello(),然后呼叫该信号的下一个处理函式,该函式呼叫 gtk_widget_destroy() 函式,把视窗元件作为参数传递给它,销毁视窗元件。这导致视窗发出 “destroy” 信号,它被捕获,并且呼叫我们的 destroy() 回呼函式,简单地退出 GTK。

如果用视窗管理员去关闭视窗,它会引发 “delete_event”。这会呼叫我们的 “delete_event” 处理函式。如果我们在函式中传回 TRUE,视窗还是留在那里,什么事也不发生。传回 FALSE,会使 GTK 发出 “destroy” 信号,它当然会呼叫 “destroy” 回呼,退出 GTK。

« 

单元首页

2 comments

Comments are closed.