GTK+编程入门(2)—GTK+程序结构

GTK+编程入门(2)—GTK+程序结构(2015-7-23)

分类:GTK+

  现在是晚上,快到睡觉时间了。把这小节完整看完是不可能了,索性就先开个头。这节的内容是通过一个最简单的GTK+程序的分析来了解GTK+程序的基本结构。
  该程序如下所示:

#include 
int main(int argc, char *argv[])
{
    //声明一个窗口构件
    GtkWidget *window;

    //初始化GTK+
    gtk_init(&argc, &argv);

    //创建主窗口
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

    //显示主窗口
    gtk_widget_show(window);

    //进入GTK+循环
    gtk_main();

    return 0;
}

  这个小窗口程序的实际效果图如下,一个空的窗口程序。
GTK+编程入门(2)—GTK+程序结构_第1张图片
  GTK+程序的编译:同样的GTK+库的头文件和库文件均不在边准目录下,编译时应当使用反引号将“pkg-config –cflags –libs gtk+-3.0”命令的执行结果替换到编译命令行。具体编译和运行命令如下:

biantiao@lazybone1994-ThinkPad-E430:~/codeblocks$ gcc -o ex_first_gtk ex_first_gtk.c `pkg-config --cflags --libs gtk+-3.0`

GTK+的数据类型

  GTK+的设计是面向对象的,一个构件就是一个对象(相信了解过WPF的同学都能够很好地理解什么是构件)。这里的构件是指的是GTK+图形界面上的一个可视组件或者容器(注意包含了两部分,不单单是可视组件,不具有可视外观的容器也算是一个构件)。
  GTK+用GtkWidget类型来表示一个构件,即,GtkWidget是可用于所有构件的通用数据类型。在以上的实例程序中第5行就定义了一个GtkWidget类型的指针变量window。
  从面向对象的角度看,GtkWidget是所有构件类的祖先类(在C++中这被称作基类或父类,很好理解,不再赘述)。下面举几个重要的例子:按钮构件(GtkButton)由容器构件(GtkContainer)派生;容器构件又由通用构件(GtkWidget)派生;GtkWidget则继承自GtkObject。GtkObject是所有GTK+类型的祖先类,用以方便地表示任何GTK+对象。
  所有创建构件的函数均返回指向GtkWidget的指针。为什么?因为GtkWidget是所有构件类型的通用数据结构,这样通用函数(比如:gtk_widget_show)可以对所有的构件进行操作。(如果对所有的构件都设计一个用于显示的show函数,你可以想象那有多麻烦。从而可以理解到以上的设计是多么地重要和明智)。
  正确的GTK+编程要求——在调用具体的构件函数之前对构件分配正确的类型。(你要注意了,这里是调用具体,具体的构件函数,因为创建构件的函数返回的是构件父类GtkWidget的指针,所以在调用属于该构件的具体的函数时,就得要求转换了,也即是上面说的分配正确类型。这是我的理解)例如,用于为窗口设置标题的gtk_window_set_title()函数,它的第一个参数为GtkWindow*类型,其原型为:

void gtk_window_set_title(GtkWindow * window, const gchar * title);

注意:GTK+中使用的数据类型并非是C语言中的数据类型,而是glib库当中定义的数据类型。
  那么,怎样才能将GtkWidget*类型的数据转换为相应的构件类型呢?记住了,每一个构件都有一个转换宏可将GtkWidget*类型转换为相应的构件类型。例如,GTK_WINDOW宏将GtkWidget*类型转换为GtkWindow*,如下所示:

gtk_window_set_title(GTK_WINDOW(window), "第一个GTK+程序");

  最后再来了解一下转换规则:子类可以安全地转换为父类,但父类一般不能转换为子类。在将一个父类指针转换为子类指针时应该确保父类指针指向的是一个子类对象。

初始化GTK+

  以上的实例程序的第7行,调用了gtk_init函数对GTK+库进行了初始化。这是任何使用GTK+库的程序所必须做的,只有在初始化之后才可以调用其它GTK+库函数。gtk_init的函数原型如下:

#include 
void gtk_init(int *argc, char ***argv);

  gtk_init函数没有返回值。如果在初始化过程中发生错误,程序会立即退出。

创建和显示窗口/构件

  初始化gtk+库后,大多数的gtk+应用程序都需要建立一个主窗口。主窗口也称为顶层窗口。第9行调用GTK_WINDOW_TOPLEVEL为参数的gtk_window_new函数建立一个新的顶层窗口。gtk_window_new函数的原型为:

GtkWidget * gtk_window_new(GtkWindowType type);

  函数唯一的参数type是一个枚举类型,定义如下:

typedef enum{
    GTK_WINDOW_TOPLEVEL,
    GTK_WINDOW_POPUP
}GtkWindowType;

  type取值为 GTK_WINDOW_TOPLEVEL 表示创建一个顶层窗口。
  和gtk_window_new函数一样,创建各种构件的函数具有一致的命名规则,即以“gtkz_”开头,后跟构件名,再以“_new”结尾。比如:gtk_label_new创建标签等。
  刚创建的构件是不可见的,必须调用gtk_widget_show函数使之可见。gtk_widget_show函数的原型如下:

void gtk_widget_show(GtkWidget *widget);

  构件具有父子关系,其中父构件是容器,子构件是包含在容器当中的构件。顶层窗口没有父构件,但可能是其它构件的容器。可以用gtk_widget_show_all来递归地显示一个容器即其所有子构件。其原型如下:

void gtk_widget_show_all(GtkWidget *widget);

GTK+的主循环

  每一个Gtk+程序在初始化及创建了主窗口之后都要调用gtk_main函数进入GTK+主循环。gtk_main函数的原型为:

void gtk_main(void);

  下面来了解GUI程序。
  GUI应用程序都是事件驱动的。这些事件大部分来自用户,比如键盘事件和鼠标事件。还有一些事件来自与系统内部,比如定时器事件,socket事件和其它I/O事件等。在没有任何事件发生的情况下,应用程序处于休眠状态。
  在主循环中,GTK+会休眠并等待x-window事件(如鼠标点击,键盘按键等),定时器或文件I/O等事件的发生。
  进入GTK+主循环后,gtk_main函数并不会自动返回,需要调用gtk_main_quit函数来终止GTK+主循环。这也是第一个GTK+程序在关闭窗口后并不会退出的原因。gtk_main_quit函数同样不带参数也没有返回值,原型如下:

void gtk_main_quit(void);

  显然,gtk_main_quit函数的最佳调用时机是关闭主窗口时候。为此,在调用gtk_main函数进入主循环之前应该为主窗口建立窗口关闭事件的处理函数,在信号处理函数中调用gtk_main_quit函数。

你可能感兴趣的:(GTK+)