一个简单的空白窗口
1 2 3 4 5 6 7 8 9 10 11 12 #include <gtk/gtk.h> int main (int argc, char ** argv) { gtk_init(&argc, &argv); GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_widget_show(window); gtk_main(); return 0 ; }
写完代码后,我们对代码进程编译,直接用gcc编译即可,但是需要加上pkg-config --cflags --libs gtk+-3.0
pkg-config 是一个为已经安装的包提供了include,以及实际库安装的位置编译选项的输出和管理的工具;
—cflags 选项作用为自动获得预处理参数,如宏定义,头文件的位置;
—libs 选项作用为自动获得链接参数,如库及依赖的其它库的位置,文件名及其它一些连接参数;
gtk+-3.0 选项作用为指定GTK版本。
具体编译命令如下: gcc demo.c -o demo pkg-config --cflags --libs gtk+-2.0
头文件〈gtk/gtk.h> 包括了GTK+中所有的控件、变量、函数和结构的声明。
gtk_init (&argc, &argv);
所有 GTK应用程序都要调用该函数,而且必须在控件定义之前使用,它为我们设置一些缺省值( 例如视觉和颜色 )映射这个函数将函数库初始化,设置缺省的信号处理函数,并检查通过命令行传递给应用程序的参数,自动完成一些必要的初始化工作。
gtk_main()
是在每个Gtk应用程序都要调用的函数。程序运行停在这里等待事件(如键盘事件或鼠标事件)的发生,等待用户来操作窗口。
GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_new()
的功能创建一个窗口并返回这个窗口的控件指针。GTK_WINDOW_TOPLEVEL指明窗口的类型为最上层的主窗口,它最常用。接着创建一个GtkWidget *类型的window变量来接收。GtkWidget是GTK+控件类型,GtkWidget * 能指向任何控件的指针类型。
gtk_widget_show(window);
用来显示上一步创建的窗口控件。 在这个简单例子里,所有事件都被忽略。用鼠标点击窗口右上角的“×”按钮也不能将窗口关闭。我们可以在终端敲 Ctrl + C 关闭程序。
控件的添加 控件是对数据和方法的封装。控件有自己的属性和方法。属性是指控件的特征。方法是指控件的一些简单而可见的功能。如按钮就是一个控件,这个按钮是方形的,里面有张图片,这是我们能看到外观属性,同时,这个按钮具备被人按下的功能。
GTK中控件主要分为两类:容器控件 ,非容器控件 。
容器控件:它可以容纳别的控件,我们可以理解为盒子,盒子拿来装东西。容器控件又分为两类,一类只能容纳一个控件 ,如窗口,按钮;另一类能容纳多个控件 ,如布局控件。
非容器控件:它不可以容纳别的控件,如标签、行编辑。
前面我们写的空白窗口是能容纳一个控件的控件,现在我们要做的是,给这个窗口添加一个按钮。
首先,我们需要创建一个按钮,然后需要把按钮添加到窗口,接着,显示按钮控件。
按钮的创建: GtkWidget *gtk_button_new_with_label(const gchar *label);
label:按钮上的字符串类型,gchar相当于C语言的char 返回值:按钮控件指针
容器添加控件: void gtk_container_add(GtkContainer *container, GtkWidget *widget);
container:容纳控件的容器 widget:要添加的控件
显示控件: void gtk_widget_show(GtkWidget *widget);
widget:需要显示的控件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 int main (int argc, char ** argv) { gtk_init(&argc, &argv); GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL); GtkWidget* button = gtk_button_new_with_label("Hello World" ); gtk_container_add(GTK_CONTAINER(window), button); gtk_widget_show(button); gtk_widget_show(window); gtk_main(); return 0 ; }
代码分析:
void gtk_container_add(GtkContainer *container, GtkWidget *widget);
这里我们是把按钮添加到窗口容器里,widget为按钮指针(以上代码的button),container为窗口指针(以上代码的window),这里需要注意的是,我们创建的窗口(window)返回值为GtkWidget *类型,而gtk_container_add()的第一个参数为GtkContainer *类型,由于 GtkWidget *类型的变量为指向任何控件的万能指针,所以,在函数传参时,根据参数类型进行相应的转换,如:gtk_container_add( (GtkContainer *)window, button);
C语言里,我们常用这种方法转换。在GTK中,很多内部变量指针类型转换都定义了宏定义,如:#define GTK_CONTAINER(x) (GtkContainer *)(x)
所以,我们还可以这么写:gtk_container_add(GTK_CONTAINER(window), button);
那么,我们如何知道,哪个类型对应哪个宏定义呢?把要转换类型名字全部变为大写,同时,单词和单词之间以下划线“_”连接,然后,这个名字就是哪个宏定义的名字,如,(GtkButton *)x用宏定义的方法为 GTK_BUTTON(x)。
假如窗口里有100个控件,还是这样一个一个地显示出来会比较麻烦,这时候,我们可以通过gtk_widget_show_all()
显示所有的控件,里面需要传的是容纳控件的那个容器(这里为窗口)。这样,容器上的控件也会跟着显示。
gtk_widget_show_all(window);// 显示窗口上的所有控件
布局容器 如果我们希望窗口里多放添加几个控件,直接添加是不成功的,因为窗口只能容纳一个控件的容器。这时候,我们需要借助布局容器,我们先把布局容器添加到窗口里,然后再把所需要添加的控件放在布局容器里。
布局容器的主要分类:水平布局( GtkHBox)、垂直布局(GtkVBox )、表格布局(GtkTable)、固定布局(GtkFixed )。
水平布局 水平布局容器的创建: GtkWidget *gtk_hbox_new( gboolean homogeneous, gint spacing );
homogeneous:容器内控件是否大小一致( gboolean 取值为TRUE 或 FALSE ) spacing:控件之间的间隔( 以像素点为单位 ),gint相当于 C语言的int 返回值:水平布局控件指针
容器添加添加控件: void gtk_container_add(GtkContainer *container, GtkWidget *widget);
container:容纳控件的容器 widget:要添加的控件
显示容器上所有控件 void gtk_widget_show_all(GtkWidget *widget);
widget:需要显示的控件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 #include <gtk/gtk.h> int main (int argc, char ** argv) { gtk_init(&argc, &argv); GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL); GtkWidget* hbox = gtk_hbox_new(TRUE, 10 ); gtk_container_add(GTK_CONTAINER(window), hbox); GtkWidget* button = gtk_button_new_with_label("button1" ); gtk_container_add(GTK_CONTAINER(hbox), button); button = gtk_button_new_with_label("button2" ); gtk_container_add(GTK_CONTAINER(hbox), button); button = gtk_button_new_with_label("button3" ); gtk_container_add(GTK_CONTAINER(hbox), button); gtk_widget_show_all(window); gtk_main(); return 0 ; }
垂直布局 垂直布局和水平布局的用法基本是一样,无非是新建垂直布局容器接口,还有控件摆放的方向不同。
垂直布局容器的创建: GtkWidget *gtk_vbox_new( gboolean homogeneous, gint spacing );
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 #include <gtk/gtk.h> int main (int argc, char ** argv) { gtk_init(&argc, &argv); GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL); GtkWidget* hbox = gtk_vbox_new(TRUE, 10 ); gtk_container_add(GTK_CONTAINER(window), hbox); GtkWidget* button = gtk_button_new_with_label("button1" ); gtk_container_add(GTK_CONTAINER(hbox), button); button = gtk_button_new_with_label("button2" ); gtk_container_add(GTK_CONTAINER(hbox), button); button = gtk_button_new_with_label("button3" ); gtk_container_add(GTK_CONTAINER(hbox), button); gtk_widget_show_all(window); gtk_main(); return 0 ; }
表格布局 学习水平和垂直布局容器后,我们几乎能布出任何风格的布局,只需要嵌套使用水平布局容器和垂直布局容器即可。假如我们要完成下图的布局,我们该怎么做呢?
1)创建一个垂直布局容器( A ) 2)创建一个水平布局容器( B ),一个close按钮( C ) 3)将水平布局容器和close按钮添加到垂直布局容器里( 将 B 和 C 添加到 A ) 4)创建button 1按钮( D ) 和 button 2按钮( E ) 5)再将button 1按钮 和 button 2按钮添加到水平布局容器里( 将 D 和 E 添加到 B )
这样是可以完成上图的布局,但是,假如布局里有有很多控件,我们只是通过水平和垂直容器嵌套布局会很麻烦,而且,控件越多,布局越麻烦。有没有更简单的方法呢?有,就是我们马上要学习的表格布局,具体的操作流程和水平垂直布局一样。
表格布局容器的创建: GtkWidget *gtk_table_new(guint rows, guint columns, gboolean homogeneous );
rows: 行数 coumns: 列数 homogeneous:容器内表格的大小是否相等 返回值:表格布局容器指针
布局容器添加控件: void gtk_table_attach_defaults(GtkTable *table, GtkWidget *widget,guint left_attach,guint right_attach,guint top_attach,guint bottom_attach );
table: 容纳控件的容器 widget: 要添加的控件? 后四个参数为控件摆放的坐标,规则如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 #include <gtk/gtk.h> int main (int argc, char ** argv) { gtk_init(&argc, &argv); GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL); GtkWidget* table = gtk_table_new(2 , 2 , TRUE); gtk_container_add(GTK_CONTAINER(window), table); GtkWidget* button = gtk_button_new_with_label("button1" ); gtk_table_attach_defaults(GTK_TABLE(table), button, 0 , 1 , 0 , 1 ); button = gtk_button_new_with_label("button2" ); gtk_table_attach_defaults(GTK_TABLE(table), button, 1 , 2 , 0 , 1 ); button = gtk_button_new_with_label("button3" ); gtk_table_attach_defaults(GTK_TABLE(table), button, 0 , 2 , 1 , 2 ); gtk_widget_show_all(window); gtk_main(); return 0 ; }
固定布局 前面我们学习的水平、垂直和表格布局容器,控件会跟着容器大小的变化进行自动适应,而固定布局容器里的控件则不会跟着变化( 则固定不变 )。
固定布局的创建: GtkWidget *gtk_fixed_new(void);
返回值:固定布局容器指针
固定布局容器添加控件: void gtk_fixed_put( GtkFixed fixed,GtkWidget widget,gint x,gint y ); fixed:容纳控件的容器 widget:要添加的控件 x, y:控件摆放位置的起点坐标
设置控件的大小( 宽和高 ): void gtk_widget_set_size_request(GtkWidget *widget,gint width,gint height );
widget:需要设置的控件 width:宽度 height:高度
移动固定布局里控件的位置: void gtk_fixed_move( GtkFixed *fixed,GtkWidget *widget,gint x,gint y);
fixed:固定布局容器 widget:需要移动的控件 x, y: 移动的位置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 #include <gtk/gtk.h> int main (int argc, char ** argv) { gtk_init(&argc, &argv); GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL); GtkWidget* fixed = gtk_fixed_new(); gtk_container_add(GTK_CONTAINER(window), fixed); GtkWidget* button = gtk_button_new_with_label("button1" ); gtk_fixed_put(GTK_FIXED(fixed), button, 50 , 50 ); GtkWidget* button2 = gtk_button_new_with_label("button2" ); gtk_fixed_put(GTK_FIXED(fixed), button2, 0 , 0 ); gtk_fixed_move(GTK_FIXED(fixed), button2, 150 , 150 ); gtk_widget_set_size_request(button2, 100 , 50 ); gtk_widget_show_all(window); gtk_main(); return 0 ; }
行编辑控件 行编辑的创建: GtkWidget * gtk_entry_new(void);
返回值:行编辑指针行
编辑内容的设置: void gtk_entry_set_text (GtkEntry *entry,const gchar *text);
entry: 行编辑 text: 需要设置的内容
设置行编辑是否允许编辑: void gtk_editable_set_editable(GtkEditable *editable, gboolean is_editable);
editable:行编辑 is_editable:TRUE代表可编辑,FALSE不允许编辑
表格布局练习之计算器1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 #include <gtk/gtk.h> int main (int argc, char * argv[]) { gtk_init(&argc, &argv); GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_widget_set_size_request(window, 270 , 320 ); GtkWidget* table = gtk_table_new(5 , 4 , TRUE); GtkWidget* entry = gtk_entry_new(); gtk_entry_set_text(GTK_ENTRY(entry), "2+2=4" ); gtk_editable_set_editable(GTK_EDITABLE(entry), FALSE); GtkWidget* button0 = gtk_button_new_with_label("0" ); GtkWidget* button1 = gtk_button_new_with_label("1" ); GtkWidget* button2 = gtk_button_new_with_label("2" ); GtkWidget* button3 = gtk_button_new_with_label("3" ); GtkWidget* button4 = gtk_button_new_with_label("4" ); GtkWidget* button5 = gtk_button_new_with_label("5" ); GtkWidget* button6 = gtk_button_new_with_label("6" ); GtkWidget* button7 = gtk_button_new_with_label("7" ); GtkWidget* button8 = gtk_button_new_with_label("8" ); GtkWidget* button9 = gtk_button_new_with_label("9" ); GtkWidget* button_add = gtk_button_new_with_label("+" ); GtkWidget* button_minus = gtk_button_new_with_label("-" ); GtkWidget* button_multiply = gtk_button_new_with_label("*" ); GtkWidget* button_divide = gtk_button_new_with_label("/" ); GtkWidget* button_equal = gtk_button_new_with_label("=" ); GtkWidget* button_detele = gtk_button_new_with_label("c" ); gtk_container_add(GTK_CONTAINER(window), table); gtk_table_attach_defaults(GTK_TABLE(table), entry, 0 , 4 , 0 , 1 ); gtk_table_attach_defaults(GTK_TABLE(table), button0, 0 , 1 , 4 , 5 ); gtk_table_attach_defaults(GTK_TABLE(table), button1, 0 , 1 , 3 , 4 ); gtk_table_attach_defaults(GTK_TABLE(table), button2, 1 , 2 , 3 , 4 ); gtk_table_attach_defaults(GTK_TABLE(table), button3, 2 , 3 , 3 , 4 ); gtk_table_attach_defaults(GTK_TABLE(table), button4, 0 , 1 , 2 , 3 ); gtk_table_attach_defaults(GTK_TABLE(table), button5, 1 , 2 , 2 , 3 ); gtk_table_attach_defaults(GTK_TABLE(table), button6, 2 , 3 , 2 , 3 ); gtk_table_attach_defaults(GTK_TABLE(table), button7, 0 , 1 , 1 , 2 ); gtk_table_attach_defaults(GTK_TABLE(table), button8, 1 , 2 , 1 , 2 ); gtk_table_attach_defaults(GTK_TABLE(table), button9, 2 , 3 , 1 , 2 ); gtk_table_attach_defaults(GTK_TABLE(table), button_add, 1 , 2 , 4 , 5 ); gtk_table_attach_defaults(GTK_TABLE(table), button_minus, 2 , 3 , 4 , 5 ); gtk_table_attach_defaults(GTK_TABLE(table), button_multiply, 3 , 4 , 2 , 3 ); gtk_table_attach_defaults(GTK_TABLE(table), button_divide, 3 , 4 , 3 , 4 ); gtk_table_attach_defaults(GTK_TABLE(table), button_equal, 3 , 4 , 4 , 5 ); gtk_table_attach_defaults(GTK_TABLE(table), button_detele, 3 , 4 , 1 , 2 ); gtk_widget_show_all(window); gtk_main(); return 0 ; }
信号与回调函数 前面我们学习的GTK界面都是静态的,我们按下按钮它是没有响应的,如何让它有响应呢?接下来我们一起学习GTK的信号与回调函数。
GTK采用了信号与回调函数来处理窗口外部传来的事件、消息或信号。当信号发生时,程序自动调用为信号连接的回调函数。
学习应用编程,我们会经常接触到“信号”这个名词。GTK中的“信号”实际上是一种软件中断。“中断”在我们生活中经常遇到,譬如,我正在房间里打游戏,突然送快递的来了,把正在玩游戏的我给“中断”了,我去签收快递( 处理中断 ),处理完成后,再继续玩我的游戏。GTK中的“信号”就是属于这么一种“中断”,当用户按下按钮的时候,就产生一个“中断”,相当于产生一个信号,接着就会处理这么一个“中断任务”(程序里体验为调用一个函数)。
“信号”在GTK中可以认为一种中断的标志,如按下按钮的标志为”pressed”,释放按钮的标志为”released”,这些标志就相当于 C 语言的关键字一样,我们使用的时候必须完全按照它的名字来写。 需要注意的是,每个控件的信号标志不一定都一样,如按钮(GtkButton)里有”pressed”信号,窗口(GtkWindow)里就没这个信号,每个控件具体有哪个信号,应该查看帮助文档来确定。
按钮的常用信号:
“clicked” : 按下按钮时触发
“pressed” : 释放按钮时触发
“released” : 释放按钮时触发
对于程序而言,我们按下按钮,是让其调用一个函数。假如有函数A, B, C,我们如何确定按下按钮后只调用函数A,而不是函数 B 或 C。这时候,我们需要一种规则规定,按下按钮后就调用函数A,就像交通规则一样,红灯走绿灯行,信号注册函数就是做这样的事情。
信号注册函数: gulong g_signal_connect( gpointer instance,const gchar *detailed_signal,GCallback c_handler, gpointer data );
instance:信号发出者,可以认为我们操作的控件,如按下按钮,这个就为按钮指针 detailed_signal:信号标志,如”pressed” c_handler:回调函数的名称,需要用G_CALLBACK()进行转换 data:给回调函数传的参数,gpointer 相当于C语言的 void * 返回值:注册函数的标志
如:g_signal_connect(button, "pressed",G_CALLBACK(callback), NULL);
当按下button按钮时,就会自动调用回调函数callback(相当于处理中断任务),回调函数callback可以是任意函数,函数名字我们根据需要自行命名,如果不是库函数,我们还得定义这个回调函数,这里需要注意的是,回调函数的写法(返回值,参数),不是我们想怎么写就怎么写,帮助文档里已经规定好了回调函数应该如何写,如果不按规定来写,可能产生意想不到的错误。
帮助文档的使用请点此处。
回调函数的定义: 1 2 3 4 5 void callback (GtkButton *button,gpointer data) { }
设置容器与控件之间的间距: void gtk_container_set_border_width(GtkContainer *container,guint border_width);
container:容器 border_width:容器与控件之间的间距,guint相当于C语言的uint
获取按钮上的文本内容: const gchar *gtk_button_get_label(GtkButton *button);
button:按钮 返回值:获取到的文本内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 #include <gtk/gtk.h> void deal_pressed (GtkButton* button, gpointer user_data) { const char * text = gtk_button_get_label(button); printf ("%s /////// %s\n" , (char *)user_data, text); } int main (int argc, char * argv[]) { gtk_init(&argc, &argv); GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_container_set_border_width(GTK_CONTAINER(window), 5 ); GtkWidget* button = gtk_button_new_with_label("^_^" ); gtk_container_add(GTK_CONTAINER(window), button); g_signal_connect(button, "pressed" , G_CALLBACK(deal_pressed), "I am a button" ); gtk_widget_show_all(window); gtk_main(); return 0 ; }
GTK简单版计算器 接下来我们做一个简单版的计算器。
获取按钮上的内容。
如果获取的内容是“ c ”,则代表进行退格操作,相当于删去最后一个字符。
如果获取的内容不是“ c ”,则把每一次获取的内容连接起来,如:第一次按了 “ 1 ”, 第二次按了 “ + ”, 第三次按了 “ 1 ”, 连起来则变为 “1+1”。
如果获取的内容是“ = ”,则需要相应的运算。先把连起来的字符串拆出来,然后再进行相应操作,最后把运算结果重新显示到行编辑上。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 #include <gtk/gtk.h> #include <string.h> char buf[50 ] = { 0 }; void deal_num (GtkButton* button, gpointer data) { const char * txt = gtk_button_get_label(button); if (0 == strcmp ("c" , txt)) { buf[strlen (buf) - 1 ] = 0 ; } else { int a = 0 , b = 0 ; char c; strcat (buf, txt); if (0 == strcmp ("=" , txt)) { sscanf (buf, "%d%c%d" , &a, &c, &b); printf ("a=%d, c = %c, b=%d\n" , a, c, b); if ('+' == c) { sprintf (buf, "%d" , a + b); } else if ('-' == c) { sprintf (buf, "%d" , a - b); } else if ('*' == c) { sprintf (buf, "%d" , a * b); } else if ('/' == c) { sprintf (buf, "%d" , a / b); } } } gtk_entry_set_text(GTK_ENTRY(data), buf); } int main (int argc, char * argv[]) { gtk_init(&argc, &argv); GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_widget_set_size_request(window, 270 , 320 ); GtkWidget* table = gtk_table_new(5 , 4 , TRUE); GtkWidget* entry = gtk_entry_new(); gtk_editable_set_editable(GTK_EDITABLE(entry), FALSE); GtkWidget* button0 = gtk_button_new_with_label("0" ); GtkWidget* button1 = gtk_button_new_with_label("1" ); GtkWidget* button2 = gtk_button_new_with_label("2" ); GtkWidget* button3 = gtk_button_new_with_label("3" ); GtkWidget* button4 = gtk_button_new_with_label("4" ); GtkWidget* button5 = gtk_button_new_with_label("5" ); GtkWidget* button6 = gtk_button_new_with_label("6" ); GtkWidget* button7 = gtk_button_new_with_label("7" ); GtkWidget* button8 = gtk_button_new_with_label("8" ); GtkWidget* button9 = gtk_button_new_with_label("9" ); GtkWidget* button_add = gtk_button_new_with_label("+" ); GtkWidget* button_minus = gtk_button_new_with_label("-" ); GtkWidget* button_multiply = gtk_button_new_with_label("*" ); GtkWidget* button_divide = gtk_button_new_with_label("/" ); GtkWidget* button_equal = gtk_button_new_with_label("=" ); GtkWidget* button_detele = gtk_button_new_with_label("c" ); gtk_container_add(GTK_CONTAINER(window), table); gtk_table_attach_defaults(GTK_TABLE(table), entry, 0 , 4 , 0 , 1 ); gtk_table_attach_defaults(GTK_TABLE(table), button0, 0 , 1 , 4 , 5 ); gtk_table_attach_defaults(GTK_TABLE(table), button1, 0 , 1 , 3 , 4 ); gtk_table_attach_defaults(GTK_TABLE(table), button2, 1 , 2 , 3 , 4 ); gtk_table_attach_defaults(GTK_TABLE(table), button3, 2 , 3 , 3 , 4 ); gtk_table_attach_defaults(GTK_TABLE(table), button4, 0 , 1 , 2 , 3 ); gtk_table_attach_defaults(GTK_TABLE(table), button5, 1 , 2 , 2 , 3 ); gtk_table_attach_defaults(GTK_TABLE(table), button6, 2 , 3 , 2 , 3 ); gtk_table_attach_defaults(GTK_TABLE(table), button7, 0 , 1 , 1 , 2 ); gtk_table_attach_defaults(GTK_TABLE(table), button8, 1 , 2 , 1 , 2 ); gtk_table_attach_defaults(GTK_TABLE(table), button9, 2 , 3 , 1 , 2 ); gtk_table_attach_defaults(GTK_TABLE(table), button_add, 1 , 2 , 4 , 5 ); gtk_table_attach_defaults(GTK_TABLE(table), button_minus, 2 , 3 , 4 , 5 ); gtk_table_attach_defaults(GTK_TABLE(table), button_multiply, 3 , 4 , 2 , 3 ); gtk_table_attach_defaults(GTK_TABLE(table), button_divide, 3 , 4 , 3 , 4 ); gtk_table_attach_defaults(GTK_TABLE(table), button_equal, 3 , 4 , 4 , 5 ); gtk_table_attach_defaults(GTK_TABLE(table), button_detele, 3 , 4 , 1 , 2 ); g_signal_connect(button0, "pressed" , G_CALLBACK(deal_num), entry); g_signal_connect(button1, "pressed" , G_CALLBACK(deal_num), entry); g_signal_connect(button2, "pressed" , G_CALLBACK(deal_num), entry); g_signal_connect(button3, "pressed" , G_CALLBACK(deal_num), entry); g_signal_connect(button4, "pressed" , G_CALLBACK(deal_num), entry); g_signal_connect(button5, "pressed" , G_CALLBACK(deal_num), entry); g_signal_connect(button6, "pressed" , G_CALLBACK(deal_num), entry); g_signal_connect(button7, "pressed" , G_CALLBACK(deal_num), entry); g_signal_connect(button8, "pressed" , G_CALLBACK(deal_num), entry); g_signal_connect(button9, "pressed" , G_CALLBACK(deal_num), entry); g_signal_connect(button_add, "pressed" , G_CALLBACK(deal_num), entry); g_signal_connect(button_minus, "pressed" , G_CALLBACK(deal_num), entry); g_signal_connect(button_multiply, "pressed" , G_CALLBACK(deal_num), entry); g_signal_connect(button_divide, "pressed" , G_CALLBACK(deal_num), entry); g_signal_connect(button_equal, "pressed" , G_CALLBACK(deal_num), entry); g_signal_connect(button_detele, "pressed" , G_CALLBACK(deal_num), entry); gtk_widget_show_all(window); gtk_main(); return 0 ; }
常用控件 窗口 窗口的创建 :GtkWidget *gtk_window_new(GtkWindowType type);
GtkWindowType是一个枚举,有两种情况:
GTK_WINDOW_TOPLEVEL:顶层窗口,有边框
GTK_WINDOW_POPUP: 弹式窗口,没边框 返回值:窗口指针
标题的设置: void gtk_window_set_title(GtkWindow *window, const gchar *title);
window:窗口 title:标题
控件最小大小的设置:
void gtk_widget_set_size_request(GtkWidget *widget,gint width,gint height);
widget:需要操作的控件,可以是任何控件 width:宽度 height:高度
窗口伸缩设置: void gtk_window_set_resizable(GtkWindow *window, gboolean resizable);
window:窗口 resizable:TURE默认属性,可伸缩,FALSE不可伸缩
显示或隐藏所有控件:1 2 void gtk_widget_show_all (GtkWidget *widget) ;void gtk_widget_hide_all (GtkWidget *widget) ;
widget:控件
窗口在显示器位置的设置:void gtk_window_set_position(GtkWindow *window, GtkWindowPosition position);
window:窗口 position常用有4种情况: GTK_WIN_POS_NONE: 不固定 GTK_WIN_POS_CENTER: 居中 GTK_WIN_POS_MOUSE: 出现在鼠标位置 GTK_WIN_POS_CENTER_ALWAYS: 窗口总是居中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 #include <gtk/gtk.h> int main (int argc, char * argv[]) { gtk_init(&argc, &argv); GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(window), "Window" ); gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); gtk_widget_set_size_request(window, 400 , 300 ); gtk_window_set_resizable(GTK_WINDOW(window), FALSE); g_signal_connect(window, "destroy" , G_CALLBACK(gtk_main_quit), NULL ); gtk_widget_show_all(window); gtk_main(); return 0 ; }
注意这一句g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
把”destroy” 和 gtk_main_quit 连接
标签 标签主要是显示文本信息,用作标志。
标签的创建: GtkWidget *gtk_label_new(const gchar *str);
str:文本内容 返回值:标签指针
设置标签的内容: void gtk_label_set_text (GtkLabel *label, const gchar *str);
label:操作的标签 str:文本内容
获取标签的内容: const gchar *gtk_label_get_text( GtkLabel *label );
label:操作的标签 返回值:获取到的文本内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 #include <gtk/gtk.h> int main (int argc, char * argv[]) { gtk_init(&argc, &argv); GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL); GtkWidget* vbox = gtk_vbox_new(TRUE, 10 ); gtk_container_add(GTK_CONTAINER(window), vbox); GtkWidget* label_one = gtk_label_new("label one" ); gtk_container_add(GTK_CONTAINER(vbox), label_one); GtkWidget* label_two = gtk_label_new("label two" ); const char * str = gtk_label_get_label(GTK_LABEL(label_two)); printf ("str = %s\n" , str); gtk_container_add(GTK_CONTAINER(vbox), label_two); GtkWidget* label_three = gtk_label_new("label three" ); gtk_label_set_text(GTK_LABEL(label_three), "change the label text" ); gtk_container_add(GTK_CONTAINER(vbox), label_three); g_signal_connect(window, "destroy" , G_CALLBACK(gtk_main_quit), NULL ); gtk_widget_show_all(window); gtk_main(); return 0 ; }
图片控件 图片控件和标签的作用很类似,都是作为显示用的,只是图片控件显示的内容是图片。
图片控件的创建: GtkWidget *gtk_image_new_from_file( const gchar *filename );
filename:图片的名字,带路径的话需要加上路径( 相对或绝对 ) 返回值:图片控件指针
通过上面方法创建的图片控件,以图片默认大小来显示,不能修改其大小。如果要改变图片的大小,我们要借助图片资源对象GdkPixbuf,需要注意的是,GdkPixbuf不属于控件类,它以 Gdk 开头。
图片资源对象pixbuf的创建:
GdkPixbuf *gdk_pixbuf_new_from_file(const gchar *filename, GError **error);
filename:图片的名字,带路径的话需要加上路径( 相对或绝对 ) error:储存错误的指针 返回值:pixbuf指针
设置图片的大小: GdkPixbuf *gdk_pixbuf_scale_simple(const GdkPixbuf *src, int dest_width, int dest_height, GdkInterpType interp_type);
src:gdk_pixbuf_new_from_file()的返回值 dest_width:图片的宽度 dest_height:图片的高度 interp_type:是一个枚举变量,标志图片的加载速度和质量,常用GDK_INTERP_BILINEAR 返回值:指定大小好的pixbuf指针
通过gdk_pixbuf_new_from_file(), gdk_pixbuf_scale_simple()创建的pixbuf,它会动态分配空间,占用资源,用完后,需要人为释放资源。
释放资源: void g_object_unref(GtkObject *object);
object:需要释放的对象
通过pixbuf来创建图片控件: GtkWidget *gtk_image_new_from_pixbuf(GdkPixbuf *pixbuf );
pixbuf:指定好大小的pixbuf 返回值:图片控件指针
图片控件重新设置一张图片(pixbuf): void gtk_image_set_from_pixbuf(GtkImage *image, GdkPixbuf *pixbuf );
image:图片控件指针 pixbuf:指定好大小的pixbuf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 #include <gtk/gtk.h> int main (int argc, char * argv[]) { gtk_init(&argc, &argv); GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL); GtkWidget* hbox = gtk_hbox_new(TRUE, 5 ); gtk_container_add(GTK_CONTAINER(window), hbox); GtkWidget* image_one = gtk_image_new_from_file("./1.jpg" ); GdkPixbuf* src = gdk_pixbuf_new_from_file("./1.jpg" , NULL ); GdkPixbuf* dst = gdk_pixbuf_scale_simple(src,100 , 100 , GDK_INTERP_BILINEAR); GtkWidget* image_two = gtk_image_new_from_pixbuf(dst); g_object_unref(src); g_object_unref(dst); gtk_container_add(GTK_CONTAINER(hbox), image_two); GdkPixbuf* tmp = gtk_image_get_pixbuf(GTK_IMAGE(image_two)); GtkWidget* image_three = gtk_image_new_from_pixbuf(tmp); gtk_container_add(GTK_CONTAINER(hbox), image_three); GtkWidget* image_four = gtk_image_new_from_file("./1.jpg" ); src = gdk_pixbuf_new_from_file("./2.jpg" , NULL ); dst = gdk_pixbuf_scale_simple(src, 200 , 200 , GDK_INTERP_BILINEAR); gtk_image_set_from_pixbuf(GTK_IMAGE(image_four), dst); g_object_unref(src); g_object_unref(dst); gtk_container_add(GTK_CONTAINER(hbox), image_four); g_signal_connect(window, "destroy" , G_CALLBACK(gtk_main_quit), NULL ); gtk_widget_show_all(window); gtk_main(); return 0 ; }
进度条 进度条的创建: GtkWidget *gtk_progress_bar_new(void);
返回值:进度条指针
设置进度条显示的进度比例: void gtk_progress_bar_set_fraction(GtkProgressBar *pbar, gdouble fraction);
pbar:需要操作的进度条 fraction:0.0到1.0
获取进度条显示的进度比例: gdouble gtk_progress_bar_get_fraction (GtkProgressBar *pbar);
pbar:需要操作的进度条 返回值:进度比例
设置滑槽上的文本显示: void gtk_progress_bar_set_text(GtkProgressBar *pbar, gchar *text);
pbar:需要操作的进度条 text:设置的文本内容
设置进度条的移动方向: void gtk_progress_bar_set_orientation(GtkProgressBar *pbar, GtkProgressBarOrientation orientation);
pbar:需要操作的进度条 orientation:移动方向,它是一个枚举变量
GTK_PROGRESS_LEFT_TO_RIGHT:从左向右
GTK_PROGRESS_RIGHT_TO_LEFT:从右向左
GTK_PROGRESS_BOTTOM_TO_TOP:从下向上
GTK_PROGRESS_TOP_TO_BOTTOM:从上向下
获取进度条的方向: GtkProgressBarOrientation gtk_progress_bar_get_orientation(GtkProgressBar *pbar);
pbar:需要操作的进度条 返回值:进度条的方向,它是一个枚举类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 #include <gtk/gtk.h> #include <string.h> void toggle_orientation (GtkWidget* widget, gpointer data) { } void callback (GtkWidget* widget, gpointer data) { gdouble new_val = gtk_progress_bar_get_fraction(GTK_PROGRESS_BAR(data)) + 0.05 ; if (new_val > 1.0 ) { new_val = 0.0 ; } gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(data), new_val); } int main (int argc, char * argv[]) { gtk_init(&argc, &argv); GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(window), "GtkProgressBar" ); gtk_container_set_border_width(GTK_CONTAINER(window), 10 ); gtk_widget_set_size_request(window, 300 , 200 ); g_signal_connect(G_OBJECT(window), "destroy" , G_CALLBACK(gtk_main_quit), NULL ); GtkWidget* vbox = gtk_vbox_new(FALSE, 5 ); gtk_container_add(GTK_CONTAINER(window), vbox); GtkWidget* progress = gtk_progress_bar_new(); gtk_container_add(GTK_CONTAINER(vbox), progress); gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress), 0.5 ); gtk_progress_bar_set_text(GTK_PROGRESS_BAR(progress), "some text" ); GtkWidget* button_orientation = gtk_button_new_with_label("Right to Left" ); g_signal_connect(button_orientation, "clicked" , G_CALLBACK(toggle_orientation), progress); gtk_container_add(GTK_CONTAINER(vbox), button_orientation); GtkWidget* button = gtk_button_new_with_label("add" ); g_signal_connect(button, "clicked" , G_CALLBACK(callback), progress); gtk_container_add(GTK_CONTAINER(vbox), button); gtk_widget_show_all(window); gtk_main(); return 0 ; }
应该是GTK3.0取消了有关进度条方向操作的原因,在回调函数toggle_orientation里直接全部取消有关操作。
按钮 空按钮的创建(按钮上没有任何内容): GtkWidget *gtk_button_new(void);
返回值:按钮指针
创建带文本内容的按钮: GtkWidget *gtk_button_new_with_label (const gchar *label);
label:文本内容 返回值:按钮指针
设置按钮的文本内容: void gtk_button_set_label(GtkButton *button, const gchar *label);
button:操作的按钮 label:要设置的文本内容
获取按钮的文本内容: const gchar *gtk_button_get_label(GtkButton *button);
button:操作的按钮 返回值:获取到的文本内容
控件使能设置: void gtk_widget_set_sensitive(GtkWidget *widget, gboolean sensitive);
widget:要操作的控件 sensitive:FALSE变灰,不允许相应响应;TRUE,正常响应
给按钮设置一张图片: void gtk_button_set_image(GtkButton *button,GtkWidget *image);
button:按钮 image:图片控件
获取按钮上的图片: GtkWidget *gtk_button_set_image(GtkButton *button);
button:按钮 返回值:图片控件
设置按钮透明背景色: void gtk_button_set_relief(GtkButton *button, newstyle);
button:按钮 newstyle: 枚举变量,GTK_RELIEF_NONE为透明
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 #include <gtk/gtk.h> int main (int argc, char * argv[]) { gtk_init(&argc, &argv); GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL); GtkWidget* hbox = gtk_hbox_new(TRUE, 10 ); gtk_container_add(GTK_CONTAINER(window), hbox); GtkWidget* normal_button = gtk_button_new_with_label("normal button" ); const char * str = gtk_button_get_label(GTK_BUTTON(normal_button)); printf ("str === %s\n" , str); gtk_button_set_label(GTK_BUTTON(normal_button), "change" ); gtk_container_add(GTK_CONTAINER(hbox), normal_button); GtkWidget* button = gtk_button_new(); GdkPixbuf* src = gdk_pixbuf_new_from_file("./1.jpg" , NULL ); GdkPixbuf* dst = gdk_pixbuf_scale_simple(src, 100 , 100 , GDK_INTERP_BILINEAR); GtkWidget* image = gtk_image_new_from_pixbuf(dst); g_object_unref(src); g_object_unref(dst); gtk_button_set_image(GTK_BUTTON(button), image); gtk_container_add(GTK_CONTAINER(hbox), button); gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE); gtk_widget_show_all(window); gtk_main(); return 0 ; }
行编辑 行编辑,只允许输入一行内容的控件,如密码输入框。
行编辑的创建: GtkWidget *gtk_entry_new(void);
返回值:行编辑指针
设置行编辑内容的最大长度: void gtk_entry_set_max_length(GtkEntry *entry, gint max);
entry:行编辑 max:长度的最大值,这里填0代表长度不作限制
设置行编辑的文本内容: void gtk_entry_set_text(GtkEntry *entry,const gchar *text);
entry:行编辑 text:文本内容
获取行编辑的内容: const gchar *gtk_entry_get_text(GtkEntry *entry);
entry:行编辑 返回值:获取到的行编辑内容
设置编辑控件是否允许编辑: void gtk_editable_set_editable(GtkEditable *editable,gboolean is_editable);
editable:需要操作的控件 is_editable:TRUE代表能允许编辑,默认属性,FALSE不允许编辑
设置行编辑的内容是否可视(不能可视相当于密码模式,看不到文本的内容) void gtk_entry_set_visibility(GtkEntry *entry,gboolean visible);
entry:行编辑 visible:TRUE可视,FALSE不可视
常用信号:”activate” 当用户在文本输入控件内部按回车键时引发activate信号;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 #include <gtk/gtk.h> void enter_callback (GtkWidget* widget, gpointer entry) { const gchar* entry_text; entry_text = gtk_entry_get_text(GTK_ENTRY(entry)); printf ("Entry contents: %s\n" , entry_text); } int main (int argc, char * argv[]) { gtk_init(&argc, &argv); GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL); g_signal_connect(window, "destroy" , G_CALLBACK(gtk_main_quit), NULL ); gtk_widget_set_size_request(window, 200 , 50 ); GtkWidget* entry = gtk_entry_new(); gtk_container_add(GTK_CONTAINER(window), entry); gtk_entry_set_max_length(GTK_ENTRY(entry), 100 ); gtk_entry_set_text(GTK_ENTRY(entry), "hello word" ); g_signal_connect(entry, "activate" , G_CALLBACK(enter_callback), entry); gtk_widget_show_all(window); gtk_main(); return 0 ; }
笔记本控件 笔记本控件,可以让用户标签式地切换多个界面。当我们需要多窗口切换时,使用笔记本控件是一个明智的选择。
笔记本控件的创建: GtkWidget *gtk_notebook_new(void);
返回值:笔记本控件指针
设置页标签的位置: void gtk_notebook_set_tab_pos( GtkNotebook *notebook, GtkPositionType pos );
notebook:笔记本控件 pos取值如下:
GTK_POS_LEFT: 左
GTK_POS_RIGHT: 右
GTK_POS_TOP: 上
GTK_POS_BOTTOM: 下
追加页面: gint gtk_notebook_append_page(GtkNotebook *notebook, GtkWidget *child, GtkWidget *tab_label );
notebook: 容纳别的控件的笔记本 child: 放在笔记本页面里的子控件 tab_label:要添加页面的标题名 返回值:成功返回值页面值(从0开始),失败返回-1
在指定位置添加页面(从0开始): gint gtk_notebook_insert_page(GtkNotebook *notebook,GtkWidget *child, tkWidget *tab_label,gint position );
notebook: 容纳别的控件的笔记本 child: 放在笔记本页面里的子控件 tab_label:要添加页面的标题名 position:页面的位置,从0开始,如果-1代表添加到最后 返回值:成功返回值页面值(从0开始),失败返回-1
设置起始页,从0开始算,相当于设置第几个页面显示: void gtk_notebook_set_current_page(GtkNotebook *notebook, gint page_num );
notebook:要设置的笔记本控件 page_num:页面数
常用信号:”switch-page” 当切换页面时,会触发”switch-page”信号
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 #include <gtk/gtk.h> void deal_switch_pape (GtkNotebook* notebook, gpointer page, guint page_num, gpointer user_data) { printf ("This is page %d\n" , page_num + 1 ); } int main (int argc, char * argv[]) { gtk_init(&argc, &argv); GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_widget_set_size_request(window, 400 , 300 ); GtkWidget* notebook = gtk_notebook_new(); gtk_container_add(GTK_CONTAINER(window), notebook); gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_LEFT); GtkWidget* label = gtk_label_new("Page one" ); GtkWidget* box = gtk_vbox_new(TRUE, 5 ); GtkWidget* button_one = gtk_button_new_with_label("I am first page" ); GtkWidget* button_two = gtk_button_new_with_label("I am first button of first page" ); gtk_container_add(GTK_CONTAINER(box), button_one); gtk_container_add(GTK_CONTAINER(box), button_two); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), box, label); label = gtk_label_new("Page two" ); box = gtk_hbox_new(TRUE, 5 ); button_one = gtk_button_new_with_label("I am second page" ); button_two = gtk_button_new_with_label("I am first button of second page" ); gtk_container_add(GTK_CONTAINER(box), button_one); gtk_container_add(GTK_CONTAINER(box), button_two); gtk_notebook_prepend_page(GTK_NOTEBOOK(notebook), box, label); button_one = gtk_button_new_with_label("insert_page" ); label = gtk_label_new("Page three" ); gtk_notebook_insert_page(GTK_NOTEBOOK(notebook), button_one, label, 1 ); g_signal_connect(notebook, "switch-page" , G_CALLBACK(deal_switch_pape), NULL ); gtk_widget_show_all(window); gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), 1 ); gtk_main(); return 0 ; }
设置窗口背景图 有问题,暂且存疑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 #include <gtk/gtk.h> void chang_background (GtkWidget* widget, int w, int h, const gchar* path) { gtk_widget_set_app_paintable(widget, TRUE); gtk_widget_realize(widget); gtk_widget_queue_draw(widget); GdkPixbuf* src_pixbuf = gdk_pixbuf_new_from_file(path, NULL ); GdkPixbuf* dst_pixbuf = gdk_pixbuf_scale_simple(src_pixbuf, w, h, GDK_INTERP_BILINEAR); GdkPixmap* pixmap = NULL ; gdk_pixbuf_render_pixmap_and_mask(dst_pixbuf, &pixmap, NULL , 200 ); gdk_window_set_back_pixmap(widget->window, pixmap, FALSE); g_object_unref(src_pixbuf); g_object_unref(dst_pixbuf); g_object_unref(pixmap); } int main (int argc, char * argv[]) { gtk_init(&argc, &argv); GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(window), "设置窗口背景图" ); gtk_widget_set_size_request(window, 500 , 450 ); chang_background(window, 500 , 400 , "./1.jpg" ); GtkWidget* hbox = gtk_hbox_new(TRUE, 50 ); gtk_container_add(GTK_CONTAINER(window), hbox); GtkWidget* normal_button = gtk_button_new_with_label("normal button" ); gtk_container_add(GTK_CONTAINER(hbox), normal_button); gtk_widget_show_all(window); gtk_main(); return 0 ; }
改变控件字体大小 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 #include <gtk/gtk.h> static void set_widget_font_size (GtkWidget* widget, int size, gboolean is_button) { GtkWidget* labelChild; PangoFontDescription* font; gint fontSize = size; font = pango_font_description_from_string("Sans" ); pango_font_description_set_size(font, fontSize * PANGO_SCALE); if (is_button) { labelChild = gtk_bin_get_child(GTK_BIN(widget)); } else { labelChild = widget; } gtk_widget_modify_font(GTK_WIDGET(labelChild), font); pango_font_description_free(font); } int main (int argc, char * argv[]) { gtk_init(&argc, &argv); GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(window), "change " ); gtk_container_set_border_width(GTK_CONTAINER(window), 10 ); gtk_widget_set_size_request(window, 500 , 450 ); GtkWidget* vbox = gtk_vbox_new(TRUE, 5 ); gtk_container_add(GTK_CONTAINER(window), vbox); GtkWidget* label = gtk_label_new("I am a label" ); set_widget_font_size(label, 50 , FALSE); gtk_container_add(GTK_CONTAINER(vbox), label); GtkWidget* button = gtk_button_new_with_label("I am a button" ); set_widget_font_size(button, 50 , TRUE); gtk_container_add(GTK_CONTAINER(vbox), button); gtk_widget_show_all(window); gtk_main(); return 0 ; }
定时器 定时器在应用编程里用得很广,我们手机里的闹钟,幻灯片播放图片等应用都用到定时器。定时器,每隔一段时间干一件事(程序里表现为调用一个函数),像闹钟,每隔一天响一次。
定时器的创建: guint g_timeout_add(guint interval, GSourceFunc function, gpointer data);
interval:设置的时间间隔,以毫秒为单位( 1000即为1秒 ) function:回调函数的名字 data:给回调函数传的参数 返回值:定时器id号
使用实例:guint timer = g_timeout_add(500, (GSourceFunc)deal_time, NULL);
每隔500ms会执行一次deal_time()回调函数。 注意:当回调函数返回值为FALSE时,定时器执行一次后便会停止工作,不再循环执行。所以,要想定时器连续工作,循环执行所指定的回调函数,应该返回TRUE。
定时器的移除:gboolean g_source_remove(guint tag);
tag:定时器id号 返回值:TRUE代表成功,FALSE代表失败
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 #include <gtk/gtk.h> #include <stdlib.h> #include <string.h> guint timer; void set_widget_font_size (GtkWidget* widget, int size, int is_button) { GtkWidget* labelChild; PangoFontDescription* font; gint fontSize = size; font = pango_font_description_from_string("Sans" ); pango_font_description_set_size(font, fontSize * PANGO_SCALE); if (is_button) { labelChild = gtk_bin_get_child(GTK_BIN(widget)); } else { labelChild = widget; } gtk_widget_modify_font(GTK_WIDGET(labelChild), font); pango_font_description_free(font); } gboolean deal_time (gpointer* label) { char buf[5 ] = "Time" ; static int num = 10 ; num--; sprintf (buf, "%d" , num); gtk_label_set_text(GTK_LABEL(label), buf); if (0 == num) { num = 11 ; } return TRUE; } int main (int argc, char * argv[]) { gtk_init(&argc, &argv); GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(window), "timer" ); gtk_container_set_border_width(GTK_CONTAINER(window), 0 ); gtk_window_set_default_size(GTK_WINDOW(window), 320 , 400 ); gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); g_signal_connect(G_OBJECT(window), "destroy" , G_CALLBACK(gtk_main_quit), NULL ); GtkWidget* label = gtk_label_new("10" ); set_widget_font_size(label, 230 , FALSE); gtk_container_add(GTK_CONTAINER(window), label); timer = g_timeout_add(1000 , (GSourceFunc)deal_time, (gpointer)label); gtk_widget_show_all(window); gtk_main(); return 0 ; }
鼠标事件 鼠标事件,可以理解为操作鼠标的动作。对于窗口而言,用户操作鼠标,窗口检测到鼠标的操作( 产生一个信号 ),然后去做相应处理( 调用其规定的回调函数 ),即可认为是鼠标事件,还是信号与回调函数的知识点。
窗口默认不接收鼠标的操作,需要手动添加让其接收。
设置控件捕获(接收)相应的事件: void gtk_widget_add_events( GtkWidget *widget, gint events );
widget:控件 events:事件类型,它是GdkEventMask的枚举常量,取值列举如下
GDK_BUTTON_PRESS_MASK:鼠标点击
GDK_BUTTON_RELEASE_MASK:鼠标释放
GDK_BUTTON_MOTION_MASK:鼠标移动
GDK_KEY_PRESS_MASK:键盘按下
GDK_ENTER_NOTIFY_MASK:进入控件区域
…… ……
鼠标点击事件产生的信号:button-press-event 鼠标释放事件产生的信号:button-release-event
其回调函数的定义如下:gboolean callback( GtkWidget *widget, GdkEventButton *event, gpointer data )
event:鼠键事件结构体变量,系统内部的变量,不是用户传参的 event->x,event->y:得到点击坐标值 event->button: 鼠标哪个键按下 event->type: 是否双击 返回值:没有太大意义
鼠标移动事件产生的信号:motion-notify-event
其回调函数的定义如下:gboolean callback( GtkWidget *widget, GdkEventMotion *event, gpointer data )
{ event->x,event->y:得到移动的坐标值 }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 #include <gtk/gtk.h> gboolean deal_mouse_press (GtkWidget *widget, GdkEventButton *event, gpointer data) { switch (event->button){ case 1 : printf ("Left Button!!\n" ); break ; case 2 : printf ("Middle Button!!\n" ); break ; case 3 : printf ("Right Button!!\n" ); break ; default : printf ("Unknown Button!!\n" ); } if (event->type == GDK_2BUTTON_PRESS){ printf ("double click\n" ); } gint i = event->x; gint j = event->y; printf ("press_x = %d, press_y = %d\n" , i, j); return TRUE; } gboolean deal_motion_notify_event (GtkWidget *widget, GdkEventMotion *event, gpointer data) { gint i = event->x; gint j = event->y; printf ("motion_x = %d, motion_y = %d\n" , i, j); return TRUE; } int main ( int argc,char *argv[] ) { gtk_init(&argc, &argv); GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(window), "mouse_event" ); gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); gtk_widget_set_size_request(window, 400 , 300 ); g_signal_connect(window, "destroy" , G_CALLBACK(gtk_main_quit), NULL ); gtk_widget_add_events(window, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_MOTION_MASK); g_signal_connect(window, "button-press-event" , G_CALLBACK(deal_mouse_press), NULL ); g_signal_connect(window, "motion-notify-event" , G_CALLBACK(deal_motion_notify_event), NULL ); gtk_widget_show_all(window); gtk_main(); return 0 ; } ```C #include <gtk/gtk.h> gboolean deal_mouse_press (GtkWidget* widget, GdkEventButton* event, gpointer data) { switch (event->button) { case 1 : printf ("Left Button!!\n" ); break ; case 2 : printf ("Middle Button!!\n" ); break ; case 3 : printf ("Right Button!!\n" ); break ; default : printf ("Unknown Button!!\n" ); } if (event->type == GDK_2BUTTON_PRESS) { printf ("double click\n" ); } gint i = event->x; gint j = event->y; printf ("press_x = %d, press_y = %d\n" , i, j); return TRUE; } gboolean deal_motion_notify_event (GtkWidget* widget, GdkEventMotion* event, gpointer data) { gint i = event->x; gint j = event->y; printf ("motion_x = %d, motion_y = %d\n" , i, j); return TRUE; } int main (int argc, char * argv[]) { gtk_init(&argc, &argv); GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(window), "mouse_event" ); gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); gtk_widget_set_size_request(window, 400 , 300 ); g_signal_connect(window, "destroy" , G_CALLBACK(gtk_main_quit), NULL ); gtk_widget_add_events(window, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_MOTION_MASK); g_signal_connect(window, "button-press-event" , G_CALLBACK(deal_mouse_press), NULL ); g_signal_connect(window, "motion-notify-event" , G_CALLBACK(deal_motion_notify_event), NULL ); gtk_widget_show_all(window); gtk_main(); return 0 ; }
键盘事件 键盘事件,可以理解为操作键盘的动作。对于窗口而言,用户操作键盘,窗口检测到键盘的操作( 产生一个信号 ),然后去做相应处理( 调用其规定的回调函数 ),即可认为是键盘事件,还是信号与回调函数的知识点。
窗口默认就能接收键盘事件,其中的键值定义在 /usr/include/gtk-2.0/gdk/gdkkeysyms.h 文件里
键盘按下事件产生的信号:key-press-event 键盘释放事件产生的信号:key-release-event
其回调函数的定义如下:gboolean callback( GtkWidget *widget, GdkEventKey *event, gpointer data )
{ event:键盘事件结构体变量,系统内部的变量,不是用户传参的 event->keyval:获取按下(释放)键盘键值,每个键值对于一个ASCII码 }
注意:可以在 GtkWidget 里找到相应的事件信号,回调函数如何定义应该查看帮助文档。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 #include <gtk/gtk.h> #include <gdk/gdkkeysyms.h> gboolean deal_key_press (GtkWidget* widget, GdkEventKey* event, gpointer data) { switch (event->keyval) { case GDK_KEY_Up: printf ("Up\n" ); break ; case GDK_KEY_Left: printf ("Left\n" ); break ; case GDK_KEY_Right: printf ("Right\n" ); break ; case GDK_KEY_Down: printf ("Down\n" ); break ; } int key = event->keyval; printf ("keyval = %d\n" , key); return TRUE; } int main (int argc, char * argv[]) { gtk_init(&argc, &argv); GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(window), "mouse_event" ); gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); gtk_widget_set_size_request(window, 400 , 300 ); g_signal_connect(window, "destroy" , G_CALLBACK(gtk_main_quit), NULL ); g_signal_connect(window, "key-press-event" , G_CALLBACK(deal_key_press), NULL ); gtk_widget_show_all(window); gtk_main(); return 0 ; }
属性改变事件 当窗口初始化,被移动或拉伸时,会触发属性改变事件。
属性改变事件产生的信号:configure_event
其回调函数的定义如下:
gboolean callback( GtkWidget *widget, GdkEventConfigure *event, gpointer data )
event:属性事件结构体变量,系统内部的变量,不是用户传参的 event->x,event->y:窗口的起点坐标 event->width,event->height:窗口的大小
以下例子为拉伸或移动窗口,能获取窗口的起点坐标以及大小:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 #include <gtk/gtk.h> gboolean on_configure_event (GtkWidget * widget, GdkEventConfigure * event, gpointer data) { gint x = event->x; gint y = event->y; printf ("x = %d, y = %d\n" , x, y); gint w = event->width; gint h = event->height; printf ("w = %d, h = %d\n" , w, h); return TRUE; } int main ( int argc, char *argv[] ) { gtk_init(&argc, &argv); GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(window), "mouse_event" ); gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); gtk_widget_set_size_request(window, 400 , 300 ); g_signal_connect(window, "destroy" , G_CALLBACK(gtk_main_quit), NULL ); g_signal_connect(window, "configure_event" , G_CALLBACK(on_configure_event), NULL ); gtk_widget_show_all(window); gtk_main(); return 0 ; }
事件盒子 有些控件( 如:标签GtkLabel,图片控件GtkImage 等),不响应GDK事件,相当于鼠标在其上面点击,它是捕获不到的。用户通过事件盒子可以解决这个问题。
事件盒子给控件提供一个GDK窗口来捕获事件。我们把控件放在事件盒子里,当我们用鼠标点击这个控件时,这个事件盒子就能捕获到点击的状态。
事件盒子的创建:
GtkWidget *gtk_event_box_new(void);
返回值:事件盒子指针
把控件添加到事件盒子里:void gtk_container_add(GtkContainer *container, GtkWidget *widget );
container:容纳控件的事件盒子 widget:要添加的控件
以下例子为,通过事件盒子实现,双击标签改变其内容:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 #include <gtk/gtk.h> gboolean button_pressed (GtkWidget* eventbox,GdkEventButton* event,GtkLabel* label) { if (event->type == GDK_2BUTTON_PRESS) { const gchar* text = gtk_label_get_text(label); if (text[0 ] == 'D' ) { gtk_label_set_text(label, "I Was Double-Clicked!" ); } else { gtk_label_set_text(label, "Double-Click Me Again!" ); } } return FALSE; } int main (int argc, char * argv[]) { gtk_init(&argc, &argv); GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(window), "Event Box" ); gtk_container_set_border_width(GTK_CONTAINER(window), 10 ); gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); gtk_widget_set_size_request(window, 200 , 50 ); g_signal_connect(window, "destroy" , G_CALLBACK(gtk_main_quit), NULL ); GtkWidget* eventbox = gtk_event_box_new(); gtk_widget_set_events(eventbox, GDK_BUTTON_PRESS_MASK); gtk_container_add(GTK_CONTAINER(window), eventbox); GtkWidget* label = gtk_label_new("Double-Click Me!" ); gtk_container_add(GTK_CONTAINER(eventbox), label); g_signal_connect(eventbox, "button_press_event" ,G_CALLBACK(button_pressed), (gpointer)label); gtk_widget_show_all(window); gtk_main(); return 0 ; }
菜单 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 #include <gtk/gtk.h> void on_menu_activate (GtkMenuItem* item,gpointer data) { g_print("Menuitem %s is pressed.\n" ,(gchar*)data); } int main (int argc, char * argv[]) { GtkWidget* window; GtkWidget* box; GtkWidget* menubar; GtkWidget* menu; GtkWidget* editmenu; GtkWidget* helpmenu; GtkWidget* rootmenu; GtkWidget* menuitem; GtkAccelGroup* accel_group ; gtk_init(&argc,&argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_widget_set_size_request(window,400 ,300 ); gtk_window_set_title(GTK_WINDOW(window),"菜单测试程序" ); g_signal_connect(G_OBJECT(window),"destroy" , G_CALLBACK(gtk_main_quit),NULL ); accel_group = gtk_accel_group_new(); gtk_window_add_accel_group(GTK_WINDOW(window),accel_group); box = gtk_vbox_new(FALSE,0 ); gtk_container_add(GTK_CONTAINER(window),box); menu = gtk_menu_new(); menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_NEW,accel_group); gtk_menu_shell_append(GTK_MENU_SHELL(menu),menuitem); g_signal_connect(G_OBJECT(menuitem),"activate" , G_CALLBACK(on_menu_activate), (gpointer)("New" )); menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_OPEN,accel_group); gtk_menu_shell_append(GTK_MENU_SHELL(menu),menuitem); g_signal_connect(G_OBJECT(menuitem),"activate" , G_CALLBACK(on_menu_activate), (gpointer)("Open" )); menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_SAVE,accel_group); gtk_menu_shell_append(GTK_MENU_SHELL(menu),menuitem); g_signal_connect(G_OBJECT(menuitem),"activate" , G_CALLBACK(on_menu_activate), (gpointer)("Save" )); menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_SAVE_AS,accel_group); gtk_menu_shell_append(GTK_MENU_SHELL(menu),menuitem); g_signal_connect(G_OBJECT(menuitem),"activate" , G_CALLBACK(on_menu_activate), (gpointer)("Save As" )); menuitem = gtk_separator_menu_item_new(); gtk_menu_shell_append(GTK_MENU_SHELL(menu),menuitem); menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_QUIT,accel_group); gtk_menu_shell_append(GTK_MENU_SHELL(menu),menuitem); g_signal_connect(G_OBJECT(menuitem),"activate" , G_CALLBACK(on_menu_activate), (gpointer)("Exit" )); rootmenu = gtk_menu_item_new_with_label(" 文件 " ); gtk_menu_item_set_submenu(GTK_MENU_ITEM(rootmenu),menu); menubar = gtk_menu_bar_new(); gtk_menu_shell_append(GTK_MENU_SHELL(menubar),rootmenu); rootmenu = gtk_menu_item_new_with_label(" 编辑 " ); editmenu = gtk_menu_new(); menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_CUT,accel_group); gtk_menu_shell_append(GTK_MENU_SHELL(editmenu),menuitem); g_signal_connect(G_OBJECT(menuitem),"activate" , G_CALLBACK(on_menu_activate), (gpointer)("Cut" )); menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_COPY,accel_group); gtk_menu_shell_append(GTK_MENU_SHELL(editmenu),menuitem); g_signal_connect(G_OBJECT(menuitem),"activate" , G_CALLBACK(on_menu_activate), (gpointer)("Copy" )); menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_PASTE,accel_group); gtk_menu_shell_append(GTK_MENU_SHELL(editmenu),menuitem); g_signal_connect(G_OBJECT(menuitem),"activate" , G_CALLBACK(on_menu_activate), (gpointer)("Paste" )); menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_FIND,accel_group); gtk_menu_shell_append(GTK_MENU_SHELL(editmenu),menuitem); g_signal_connect(G_OBJECT(menuitem),"activate" , G_CALLBACK(on_menu_activate), (gpointer)("Search" )); gtk_menu_item_set_submenu(GTK_MENU_ITEM(rootmenu),editmenu); gtk_menu_shell_append(GTK_MENU_SHELL(menubar),rootmenu); rootmenu = gtk_menu_item_new_with_label(" 帮助 " ); helpmenu = gtk_menu_new(); menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_HELP,accel_group); gtk_menu_shell_append(GTK_MENU_SHELL(helpmenu),menuitem); g_signal_connect(G_OBJECT(menuitem),"activate" , G_CALLBACK(on_menu_activate), (gpointer)("Help" )); menuitem = gtk_menu_item_new_with_label(" 关于... " ); gtk_menu_shell_append(GTK_MENU_SHELL(helpmenu),menuitem); g_signal_connect(G_OBJECT(menuitem),"activate" , G_CALLBACK(on_menu_activate), (gpointer)("About" )); gtk_menu_item_set_submenu(GTK_MENU_ITEM(rootmenu),helpmenu); gtk_menu_shell_append(GTK_MENU_SHELL(menubar),rootmenu); gtk_box_pack_start(GTK_BOX(box),menubar,FALSE,FALSE,0 ); gtk_widget_show_all(window); gtk_main(); return FALSE; }