1. Hello World
GTK 是事件驱动的工具包。
从数据处理角度,当一个事件发生时,如点击一次鼠标,所按的构件便会发出信号。所以使用 GTK 编写 hello world 时,构件需要与信号进行绑定。信号和构件的绑定函数有两种:g_signal_connect 与 g_signal_connect_swapped(https://blog.csdn.net/shaoguangleo/article/details/6852689)。两者最大的不同点为,g_signal_connect() 函数绑定时回调函数是两个参数,主要目的是为了接收用户传入的数据。g_signal_connect_swapped() 函数绑定时回调函数仅接收一个参数(构件对象),目的是为了处理构件的相关操作,而不是数据。
对于 UI 界面,不同构件之间的绑定需要注意类型的强转。窗口,容器,按钮盒,按钮之间的关系一定要理清:按钮绑定在按钮盒,按钮盒绑定在窗口。绑定时需要将被绑定对象转为容器进行绑定,例如按钮绑定在按钮盒,此时按钮盒需要强转为容器;按钮盒绑定在窗口,窗口需要强转为容器。
#include <gtk/gtk.h>
/*
* 定义一个打印函数,在点击按钮时调用该函数
* @param widget: 相当于GtkContainer 容器类的父类
* @param data: 用户点击按钮时传入的数据
*/
static void print_hello(GtkWidget *widget, gpointer data){
g_print("hello world!\n");
}
// 程序创建时调用的 activate 函数
static void activate(GtkApplication *app, gpointer user_data){
// 1. 设置窗口
// 为程序创建一个窗口
GtkWidget *window = gtk_application_window_new(app);
// 设定窗口名称,接收 GtkWindow* 类型的参数,故需要强转(GtkWidget可看作是GtkWindow的父类)
gtk_window_set_title(GTK_WINDOW(window), "HelloWorld");
// 设定窗口大小,接收 GtkWindow* 类型的参数
gtk_window_set_default_size(GTK_WINDOW(window), 400, 400);
// 2. 设置窗口内部各组件
// 设定按钮盒子,里面可以存放多个按钮,接收的参数含义为按钮横向排列
GtkButtonBox *button_box = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
// 设定按钮
GtkButton *button = gtk_button_new_with_label("Hello World");
// 将按钮与按钮盒绑定在一起,接收参数类型为 GtkContainer*,故此处进行强转
gtk_container_add(GTK_CONTAINER(button_box), button);
// 将按钮盒与窗口绑定在一起
gtk_container_add(GTK_CONTAINER(window), button_box);
// 3. 按钮绑定两个事件
// 绑定按钮点击事件,点击时执行函数print_hello。执行该函数时传入数据为NULL,即print_hello函数第二个参数接收为NULL
g_signal_connect(button, "clicked", G_CALLBACK(print_hello), NULL);
// 绑定按钮事件,点击后自动退出该窗口,故回调函数功能为退出窗口,参数为窗口对象window
// g_signal_connect_swapped()回调函数仅传一个参数,一个指向 GTK 对象的指针
g_signal_connect_swapped(button, "clicked", G_CALLBACK(gtk_window_close), window);
// 4. 显示窗口, 传入窗口对象window
gtk_widget_show_all(window);
}
int main(int argc, char **argv) {
// 创建一个程序
GtkApplication *app = gtk_application_new("com.gltzlike.clang", G_APPLICATION_FLAGS_NONE);
// 程序创建时发出信号,进行相应的函数绑定
// 绑定的对象是程序app,绑定信号是“activate”,绑定的函数名称为 activate,绑定时需要传入的数据为NULL
g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
// 运行该程序,返回状态码
// 接收参数,其中第一个参数为GApplication *,是GtkApplication的父类;
// 第二个和第三个参数是主程序参数(主程序运行时的参数),argc:传入的参数个数,argv:传入的参数字符串数组
int status = g_application_run(app, argc, argv);
// g_application_run() 函数启动后,会陷入死循环,一直监听窗口的动态(例如移动窗口,点击窗口),直到窗口退出才会返回status
// 窗口退出后,需要释放内存
// 调用g_object_unref()函数解引用,让app有资格释放内存
g_object_unref(app);
return status;
}
最终程序运行结果如下,启动该程序,弹出窗口。
点击 Hello World 按钮,控制台输出 "hello world!",同时窗口退出。