写在前面的话:
- 版权声明:本文为博主原创文章,转载请注明出处!
- 博主是一个小菜鸟,并且非常玻璃心!如果文中有什么问题,请友好地指出来,博主查证后会进行更正,啾咪~~
- 每篇文章都是博主现阶段的理解,如果理解的更深入的话,博主会不定时更新文章。
- 本文初次更新时间:2020.8.6,最后更新时间:2020.10.23
前言
网上有太多 GTK+ 2 的教程了,看了一下 GTK+ 已经出到4了,综合一下打算写一下 GTK+ 3。
有兴趣的话也可以自己查看官方手册:
正文开始
创建一个200 × 200像素的空窗口
运行效果如图:
源代码
代码文件demo.c
:
#include <gtk/gtk.h>
static void activate (GtkApplication* app, gpointer user_data)
{
GtkWidget *window;
window = gtk_application_window_new (app);
gtk_window_set_title (GTK_WINDOW (window), "Window");
gtk_window_set_default_size (GTK_WINDOW (window), 200, 200);
gtk_widget_show_all (window);
}
int main (int argc, char **argv)
{
GtkApplication *app;
int status;
app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
status = g_application_run (G_APPLICATION (app), argc, argv);
g_object_unref (app);
return status;
}
编译指令
gcc `pkg-config --cflags gtk+-3.0` -o demo demo.c `pkg-config --libs gtk+-3.0`
代码解析
GTK+头文件:gtk/gtk.h
main() 函数
main() 函数的作用是创建GtkApplication
对象并运行它。
int main (int argc, char **argv)
{
GtkApplication *app;
int status;
app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE); //创建GtkApplication对象
g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
status = g_application_run (G_APPLICATION (app), argc, argv);
g_object_unref (app);
return status;
}
gtk_application_new()
app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
GtkApplication
是 Application 类。gtk_application_new()
用于创建GtkApplication实例。
GtkApplication *
gtk_application_new (const gchar *application_id,
GApplicationFlags flags);
该函数文档可以点这里。
- 参数
application_id
:应用程序标识符(名称),GTK+ 3.6或更高版本允许使用null
,该参数详情看这里。 - 参数
flags
:应用程序标志。 - 返回值:返回一个新的GtkApplication实例。
g_signal_connect()
g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
这里将激活信号连接到activate()函数。
#define g_signal_connect(instance, detailed_signal, c_handler, data)
- 参数
instance
:连接的实例 - 参数
detailed_signal
:字符串,详细信号,看下面信号详情。 - 参数
c_handler
:连接的回调函数 - 参数
data
:数据传递给c_handler调用 - 返回值:Gulong 类型的处理程序 ID (成功连接时总是大于0)
GtkApplication的一组应用程序应该响应的信号
:
startup
:在应用程序第一次启动时设置shutdown
:执行关闭任务activate
:显示应用程序的默认第一个窗口,对应于桌面环境正在启动的应用程序。open
:打开文件并在新窗口中显示它们,对应于有人试图从文件浏览器或类似的应用程序打开文档。
当应用程序启动时,将触发startup
信号,可以执行一些初始化任务。之后,根据应用程序的启动方式,接下来将调用 activate
或 open
。
GtkApplication 默认将应用程序设为单实例。如果用户尝试启动第二个实例,则GtkApplication 将向第一个实例发出信号,你将收到其他activate
或open
信号。在这种情况下,第二个实例将立即退出,而不调用 startup
或 shutdown
。
在关闭任务时,将会收到一个shutdown
信号,可以执行一些清理任务(例如将文件保存到磁盘)。
文档指出,main() 函数应该尽可能小,除了创建和运行 GtkApplication 之外几乎什么都不做。真正的工作
应该始终根据 GtkApplication 触发的信号来完成。
g_application_run()
status = g_application_run (G_APPLICATION (app), argc, argv);
当应用程序运行g_application_run()
启动时,将发送activate
信号。gtk_application_run()还将指向命令行参数计数器和字符串数组的指针作为参数; 这使GTK+可以解析控制GTK+本身行为的特定命令行参数。解析后的参数将从数组中删除,将无法识别的参数留给应用程序解析。
int
g_application_run (GApplication *application,
int argc,
char **argv);
运行应用程序。该函数详情可以点这里。
- 参数
application
:应用程序 - 参数
argc
:main()
中的argc
(如果argv
为NULL
,则为0
) - 参数
argv
:main()
中的argv
,或NULL
- 返回值:exit 的状态
g_object_unref()
g_object_unref (app);
使用g_object_unref()
从内存中释放GtkApplication
对象。
void
g_object_unref (gpointer object);
activate() 函数
static void activate (GtkApplication* app, gpointer user_data)
{
GtkWidget *window;
window = gtk_application_window_new (app);
gtk_window_set_title (GTK_WINDOW (window), "Window");
gtk_window_set_default_size (GTK_WINDOW (window), 200, 200);
gtk_widget_show_all (window);
}
当应用程序运行g_application_run()
启动时,将发送activate
信号,该信号发送后,将进入应用程序的activate()
函数。在该函数内部,要构造GTK窗口,以便在启动应用程序时显示一个窗口。
gtk_application_window_new()
GtkWidget *window;
window = gtk_application_window_new (app);
调用gtk_application_window_new()
将创建一个新的GtkWindow并将其存储在window指针中。
GtkWidget *
gtk_application_window_new (GtkApplication *application);
创建一个新的GtkWindow。
gtk_window_set_title()
gtk_window_set_title (GTK_WINDOW (window), "Window");
使用gtk_window_set_title()
设置窗口标题
。
void
gtk_window_set_title (GtkWindow *window,
const gchar *title);
- 参数
window
:一个 GtkWindow - 参数
title
:窗口的标题
此函数将GtkWindow*
和字符串
作为输入。由于window指针是GtkWidget*
,因此需要将其强制转换为GtkWindow*
,但不是用 (GtkWindow*)强制执行window转换, 而是使用宏GTK_WINDOW()
。
GTK_WINDOW()
会在强制转换之前检查指针是否为GtkWindow类的实例,并在检查失败时发出警告。有关此约定的更多信息,请参见此处。
gtk_window_set_default_size()
gtk_window_set_default_size (GTK_WINDOW (window), 200, 200);
该函数用于设置窗口大小。
void
gtk_window_set_default_size (GtkWindow *window,
gint width,
gint height);
设置窗口的默认大小。该函数详情可以点这里。
- 参数
window
:一个 GtkWindow - 参数
width
:宽度(单位:像素),或者-1
来取消默认宽度 - 参数
height
:高度(单位:像素),或者-1
来取消默认高度
gtk_widget_show_all()
gtk_widget_show_all (window);
通过gtk_widget_show_all()
来显示窗口。
void
gtk_widget_show_all (GtkWidget *widget);
递归地显示一个小部件和小部件里的所有子小部件。
创建一个有按钮的窗口
运行效果如图:
源代码
该代码是在上面的demo.c
的基础上改的,在窗口增加了按钮,按钮标签为Hello World
。
#include <gtk/gtk.h>
static void print_hello (GtkWidget *widget, gpointer data)
{
g_print ("Hello World\n");
}
static void activate (GtkApplication *app, gpointer user_data)
{
GtkWidget *window;
GtkWidget *button;
GtkWidget *button_box;
window = gtk_application_window_new (app);
gtk_window_set_title (GTK_WINDOW (window), "Window");
gtk_window_set_default_size (GTK_WINDOW (window), 200, 200);
button_box = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
gtk_container_add (GTK_CONTAINER (window), button_box);
button = gtk_button_new_with_label ("Hello World");
g_signal_connect (button, "clicked", G_CALLBACK (print_hello), NULL);
g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_widget_destroy), window);
gtk_container_add (GTK_CONTAINER (button_box), button);
gtk_widget_show_all (window);
}
int main (int argc, char **argv)
{
GtkApplication *app;
int status;
app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
status = g_application_run (G_APPLICATION (app), argc, argv);
g_object_unref (app);
return status;
}
代码解析
这里main()函数同上。
activate()
static void activate (GtkApplication *app, gpointer user_data)
{
GtkWidget *window;
GtkWidget *button;
GtkWidget *button_box;
window = gtk_application_window_new (app);
gtk_window_set_title (GTK_WINDOW (window), "Window");
gtk_window_set_default_size (GTK_WINDOW (window), 200, 200);
button_box = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
gtk_container_add (GTK_CONTAINER (window), button_box);
button = gtk_button_new_with_label ("Hello World");
g_signal_connect (button, "clicked", G_CALLBACK (print_hello), NULL);
g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_widget_destroy), window);
gtk_container_add (GTK_CONTAINER (button_box), button);
gtk_widget_show_all (window);
}
看一下activate()函数不同的部分:
声明了button
、button_box
两个新的GtkWidget指针
来实现。
button_box变量用于存储GtkButtonBox。GtkButtonBox是GTK+控制按钮的大小和布局的方式,即用来排列按钮的容器。
gtk_button_box_new()
button_box = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
gtk_button_box_new()
用于创建一个新的GtkButtonBox
。
GtkWidget *
gtk_button_box_new (GtkOrientation orientation);
- 参数
orientation
:盒子的朝向,GtkOrientation
枚举,即该盒子包含的按钮是水平方式或垂直方式存储。
在这里只处理一个按钮,所以方向无所谓。
gtk_container_add()
gtk_container_add (GTK_CONTAINER (window), button_box);
在初始化button_box之后,使用gtk_container_add()
将button_box小部件添加到窗口小部件中。
这里,对应关系如下:
未完待续~~