1. 介绍这里说一下我为什么要学GTK。
当时软工老师让C语言写一个管理系统,体会面向过程的特点。然后我就想着搞个图形界面的会酷点,选择了GTK这个GUI库。
因为我是想在我的windows上使用GTK库,结合我的visual studio2019一起使用,有一点了解的朋友们应该知道,gtk主要就是用在linux上,所以在windows上搞真的问题多多,在网上搜了很多,也没有一个能教在visual studio2019 windows环境下配置GTK的,真的太不容易了。
等过些天我有时间了,会将下面的代码都加上注释,并且配上运行效果图,也会写一篇在visual studio 2019 windows环境下配置GTK的博客,也会记录我使用GTK做软工大作业的过程,有兴趣的朋友可以继续关注我噢!⭐
是一款纯C的GUI库,简单、强大,Flat API,不需要面向对象的知识,用纯面向过程编写代码。
2. 测试代码#includeint main(int argc, char* argv[]) { GtkWidget* window; GtkWidget* label; gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(window), "Hello World"); g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL); label = gtk_label_new("Hello, World"); gtk_container_add(GTK_CONTAINER(window), label); gtk_widget_show_all(window); gtk_main(); return 0; }
注意❗:如果涉及到中文字符串,在windows环境下,默认用的是GB2312,会乱码。有以下两种解决方法:
- 将代码文件保存为utf-8无签名版(注意一定是无签名版)
- 使用我后面的代码,我封装好了函数调用,将中文字符串转为utf-8进行显示输出。(推荐)
这里我说一下为什么推荐,因为utf-8无签名版,在编译小陌白这个中文的时候会莫名出错,编译小陌白呀就不会,我了解的不是很深,所以我这就称它为玄学错误吧,但第二种方法目前在我使用的过程中,没有再产生任何玄学错误,所以,强烈推荐第二种方法。
3. GTK基础 3.1 GTKWidget基本操作和命名规则-
Widget:控件,主要控件继承体系,儿子具有父亲的能力。
-
Widget基本操作:
- 因为界面上可能会有多个控件,所以调用方法的时候要传递控件的标识。
- void gtk_widget_show(widget):显示
- void gtk_widget_hide(widget):隐藏
- void gtk_widget_set_sentitive(widget, sensitive):对控件进行禁用或启用。第一个参数是传入要被启用或者禁用的控件,第二个参数是一个boolean值,true就是启用,false就是禁用。
- void gtk_widget_set_size_request(int widget, int width, int height):设置一个控件的"建议"大小,并不是最终的大小,最终的大小取决于布局的计算。
- void gtk_widget_destroy(widget):销毁一个控件
-
Window基本操作:
- gtk_window_set_resizable(window, resizable):设置窗口是否可以缩放。第二个参数是boolean,true就是可以,false是不可以。
- gtk_window_set_position(window, GTK_WIN_POS_CENTER_ALWAYS):设置窗口显示在屏幕正中央。
- void gtk_window_maximize(window):最大化
- void gtk_container_add(container, widget):将一个子控件加到父控件当中。
-
gtk命名规则:
- 一般以gtk_开头
- gtk_widget_代表这个函数可以应用于GtkWidget及所有子类。gtk_container_代表这个函数可以应用于GtkContainer及所有子类。
- gtk_***_new,创建一个***类型的控件并返回它的标识(编号)。
- gtk_AAA_get_BBB,从AAA类型的控件的标识获得控件的BBB属性的值。
- gtk_AAA_set_BBB,设置指定标识的类型为AAA的控件的BBB属性的值。
-
文本框(GtkEntry)
#include
int main(int argc, char* argv[]) { GtkWidget* window; gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(window), "中文"); g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL); //1.创建一个行编辑 GtkWidget* entry = gtk_entry_new(); //2.设置行编辑显示最大字符的长度 gtk_entry_set_max_length(GTK_ENTRY(entry), 100); //设置行编辑的内容 gtk_entry_set_text(GTK_ENTRY(entry), "hello entry"); gtk_container_add(GTK_CONTAINER(window), entry); gtk_widget_show_all(window); gtk_main(); return 0; } -
按钮(GtkButton)
#include
int main(int argc, char* argv[]) { GtkWidget* window; gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(window), "中文"); g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL); // 创建一个按钮 GtkWidget* btn1 = gtk_button_new(); gtk_button_set_label(GTK_BUTTON(btn1), "点我呀"); gtk_container_add(GTK_CONTAINER(window), btn1); gtk_widget_show_all(window); gtk_main(); return 0; } -
标签(GtkLabel)
#include
int main(int argc, char* argv[]) { GtkWidget* window; gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(window), "中文"); g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL); GtkWidget* label = gtk_label_new("你好"); gtk_container_add(GTK_CONTAINER(window), label); gtk_widget_show_all(window); gtk_main(); return 0; }
-
window中最多只能有一个子控件,一般窗口都有很多子控件,怎么办?
答:使用容器控件。window中放容器控件,其他控件都放容器控件中。
-
使用:
#include
int main(int argc, char* argv[]) { GtkWidget* window; gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(window), "中文"); g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL); GtkWidget* box1 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); GtkWidget* btn1 = gtk_button_new(); gtk_button_set_label(GTK_BUTTON(btn1), "text"); gtk_box_pack_start(GTK_BOX(box1), btn1, false, false, 0); GtkWidget* btn2 = gtk_button_new(); gtk_button_set_label(GTK_BUTTON(btn2), "text2"); gtk_box_pack_start(GTK_BOX(box1), btn2, false, false, 0); gtk_container_add(GTK_CONTAINER(window), box1); gtk_widget_show_all(window); gtk_main(); return 0; }
#include4. GTK深入 4.1 使用信号获得按钮点击消息int main(int argc, char* argv[]) { GtkWidget* window; gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(window), "中文"); g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL); GtkWidget* grid = gtk_grid_new(); GtkWidget* btn1 = gtk_button_new(); gtk_button_set_label(GTK_BUTTON(btn1), "text"); gtk_grid_attach(GTK_GRID(grid), btn1, 0, 0, 1, 1); // 左边距,距离顶部边距,宽高 GtkWidget* btn2 = gtk_button_new(); gtk_button_set_label(GTK_BUTTON(btn2), "text2"); gtk_grid_attach(GTK_GRID(grid), btn2, 1, 0, 1, 1); GtkWidget* btn3 = gtk_button_new(); gtk_button_set_label(GTK_BUTTON(btn3), "text3"); gtk_grid_attach(GTK_GRID(grid), btn3, 0, 1, 2, 2); gtk_container_add(GTK_CONTAINER(window), grid); gtk_widget_show_all(window); gtk_main(); return 0; }
#include4.2 复选按钮GtkCheckButton#include char* _(char* c) { // 解决中文不显示问题 return(g_locale_to_utf8(c, -1, 0, 0, 0)); } char* _2(const char* c) { return(g_locale_to_utf8(c, -1, 0, 0, 0)); } int btn1Onclicked(GtkWidget* widget, int data); GtkWidget* window; int main(int argc, char* argv[]) { gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(window), _2("中文")); g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL); GtkWidget* btn1 = gtk_button_new_with_label("ok"); g_signal_connect(btn1, "clicked", G_CALLBACK(btn1Onclicked), NULL); gtk_container_add(GTK_CONTAINER(window), btn1); gtk_widget_show_all(window); gtk_main(); return 0; } int btn1Onclicked(GtkWidget* widget, int data) { gtk_window_set_title(GTK_WINDOW(window), _2("小陌白")); return 0; }
#include4.3 单选按钮GtkRadioButton#include int cbAgreeOnClick(GtkWidget* widget, int data); char* _(char* c) { return(g_locale_to_utf8(c, -1, 0, 0, 0)); } char* _2(const char* c) { return(g_locale_to_utf8(c, -1, 0, 0, 0)); } GtkWidget* window; GtkWidget* cbAgree; GtkWidget* btnInstall; int main(int argc, char* argv[]) { gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(window), _2("中文")); g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL); GtkWidget* box1 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); cbAgree = gtk_check_button_new_with_label(_2("我同意")); gtk_box_pack_start(GTK_BOX(box1), cbAgree, false, false, 0); g_signal_connect(cbAgree, "clicked", G_CALLBACK(cbAgreeOnClick), NULL); btnInstall = gtk_button_new_with_label(_2("安装")); gtk_box_pack_start(GTK_BOX(box1), btnInstall, false, false, 0); gtk_widget_set_sensitive(btnInstall, false); //GtkWidget* cb1 = gtk_check_button_new(); //gtk_button_set_label(GTK_BUTTON(cb1), _2("男")); // printf("%d", gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cb1))); gtk_container_add(GTK_CONTAINER(window), box1); gtk_widget_show_all(window); gtk_main(); return 0; } int cbAgreeOnClick(GtkWidget* widget, int data) { int checked = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cbAgree)); gtk_widget_set_sensitive(btnInstall, checked); return 0; }
#include4.4 Label和Entry的更多函数#include char* _(char* c) { return(g_locale_to_utf8(c, -1, 0, 0, 0)); } char* _2(const char* c) { return(g_locale_to_utf8(c, -1, 0, 0, 0)); } GtkWidget* window; int main(int argc, char* argv[]) { gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(window), _2("中文")); g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL); GtkWidget* box1 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); GtkWidget* rbMale = gtk_radio_button_new_with_label(NULL, _2("男")); GtkWidget* rbFeMale = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(rbMale), _2("女")); gtk_box_pack_start(GTK_BOX(box1), rbMale, false, false, 0); gtk_box_pack_start(GTK_BOX(box1), rbFeMale, false, false, 0); gtk_container_add(GTK_CONTAINER(window), box1); gtk_widget_show_all(window); gtk_main(); return 0; }
#include4.5 下拉选择框GtkComboBoxText#include int btnCheckedOnClicked(GtkWidget* widget, int data); char* _(char* c) { return(g_locale_to_utf8(c, -1, 0, 0, 0)); } char* _2(const char* c) { return(g_locale_to_utf8(c, -1, 0, 0, 0)); } GtkWidget* window; GtkWidget* entryName; GtkWidget* btnCheck; GtkWidget* labelResult; int main(int argc, char* argv[]) { gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(window), _2("中文")); g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL); GtkWidget* box1 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); entryName = gtk_entry_new(); gtk_entry_set_max_length(GTK_ENTRY(entryName), 5); // 限制输入的最大长度 gtk_entry_set_visibility(GTK_ENTRY(entryName), false); // 设置为密码框的风格 btnCheck = gtk_button_new_with_label(_2("鉴定")); labelResult = gtk_label_new(""); g_signal_connect(btnCheck, "clicked", G_CALLBACK(btnCheckedOnClicked), NULL); gtk_box_pack_start(GTK_BOX(box1), entryName, false, false, 0); gtk_box_pack_start(GTK_BOX(box1), btnCheck, false, false, 0); gtk_box_pack_start(GTK_BOX(box1), labelResult, false, false, 0); gtk_container_add(GTK_CONTAINER(window), box1); gtk_widget_show(window); gtk_widget_show_all(window); gtk_main(); return 0; } int btnCheckedOnClicked(GtkWidget* widget, int data) { const char* name = gtk_entry_get_text(GTK_ENTRY(entryName)); char msg[50] = { 0 }; sprintf(msg, _2("经鉴定%s是世界上最帅的人"), name); gtk_label_set_text(GTK_LABEL(labelResult), msg); return 0; }
#include#include #include int cmbGirlChange(GtkWidget* widget, int data); char* _(char* c) { return(g_locale_to_utf8(c, -1, 0, 0, 0)); } char* _2(const char* c) { return(g_locale_to_utf8(c, -1, 0, 0, 0)); } GtkWidget* window; GtkWidget* cmbGirl; GtkWidget* labelResult; int main(int argc, char* argv[]) { gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(window), _2("中文")); g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL); GtkWidget* box1 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); cmbGirl = gtk_combo_box_text_new(); gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(cmbGirl), "hndx", _2("河南大学")); gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(cmbGirl), "jsj", _2("计算机")); gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(cmbGirl), "ltq", _2("龙亭区")); gtk_combo_box_set_active_id(GTK_COMBO_BOX(cmbGirl), "hndx"); // 设置id="hndx"的行项被默认选中 labelResult = gtk_label_new(""); g_signal_connect(cmbGirl, "changed", G_CALLBACK(cmbGirlChange), NULL); gtk_box_pack_start(GTK_BOX(box1), cmbGirl, false, false, 0); gtk_box_pack_start(GTK_BOX(box1), labelResult, false, false, 0); gtk_container_add(GTK_CONTAINER(window), box1); gtk_widget_show(window); gtk_widget_show_all(window); gtk_main(); return 0; } int cmbGirlChange(GtkWidget* widget, int data) { const char* id = gtk_combo_box_get_active_id(GTK_COMBO_BOX(cmbGirl)); if (strcmp(id, "hndx") == 0) {// 返回0代表字符串相等 gtk_label_set_text(GTK_LABEL(labelResult), _2("河南大学欢迎你!")); } else if (strcmp(id, "龙亭区") == 0) { gtk_label_set_text(GTK_LABEL(labelResult), _2("河南省开封市龙亭区欢迎你!")); } else { gtk_label_set_text(GTK_LABEL(labelResult), _2("来一起在计算机的世界遨游吧!")); } return 0; }
- 省市选择器
#include4.6 工具栏GtkToolBar#include #include int cmbProvChange(GtkWidget* widget, int data); char* _(char* c) { return(g_locale_to_utf8(c, -1, 0, 0, 0)); } char* _2(const char* c) { return(g_locale_to_utf8(c, -1, 0, 0, 0)); } GtkWidget* window; GtkWidget* cmbProv; // 省 GtkWidget* cmbCity; // 城市 int main(int argc, char* argv[]) { gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(window), _2("中文")); g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL); GtkWidget* box1 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); cmbProv = gtk_combo_box_text_new(); gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(cmbProv), "gds", _2("广东省")); gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(cmbProv), "hns", _2("河南省")); gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(cmbProv), "hbs", _2("河北省")); gtk_combo_box_set_active_id(GTK_COMBO_BOX(cmbProv), "hns"); // 设置id="hndx"的行项被默认选中 cmbCity = gtk_combo_box_text_new(); g_signal_connect(cmbProv, "changed", G_CALLBACK(cmbProvChange), NULL); gtk_box_pack_start(GTK_BOX(box1), cmbProv, false, false, 0); gtk_box_pack_start(GTK_BOX(box1), cmbCity, false, false, 0); gtk_container_add(GTK_CONTAINER(window), box1); gtk_widget_show(window); gtk_widget_show_all(window); gtk_main(); return 0; } int cmbProvChange(GtkWidget* widget, int data) { gtk_combo_box_text_remove_all(GTK_COMBO_BOX_TEXT(cmbCity)); // 先清理旧的数据 const char* id = gtk_combo_box_get_active_id(GTK_COMBO_BOX(cmbProv)); if (strcmp(id, "hbs") == 0) { gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(cmbCity), "hss", _2("衡水市")); gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(cmbCity), "bds", _2("保定市")); } else if (strcmp(id, "gds") == 0) { gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(cmbCity), "gzs", _2("广州市")); gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(cmbCity), "bds", _2("深圳市")); } else { gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(cmbCity), "kfs", _2("开封市")); gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(cmbCity), "zzs", _2("郑州市")); } return 0; }
#include#include #include char* _(char* c) { return(g_locale_to_utf8(c, -1, 0, 0, 0)); } char* _2(const char* c) { return(g_locale_to_utf8(c, -1, 0, 0, 0)); } GtkWidget* window; int main(int argc, char* argv[]) { gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(window), _2("中文")); g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL); GtkWidget* box1 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); GtkWidget* toolbar = gtk_toolbar_new(); GtkToolItem* btn1 = gtk_tool_button_new(NULL, _2("保存")); gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(btn1), GTK_STOCK_SAVE); gtk_toolbar_insert(GTK_TOOLBAR(toolbar), btn1, 0); GtkToolItem* btn2 = gtk_tool_button_new(NULL, _2("退出")); gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(btn2), GTK_STOCK_DISCONNECT); // 加图标 gtk_toolbar_insert(GTK_TOOLBAR(toolbar), btn2, 1); gtk_box_pack_start(GTK_BOX(box1), toolbar, false, false, 0); gtk_container_add(GTK_CONTAINER(window), box1); gtk_widget_show(window); gtk_widget_show_all(window); gtk_main(); return 0; }



