GTK
这里说一下我为什么要学GTK。
当时软工老师让C语言写一个管理系统,体会面向过程的特点。然后我就想着搞个图形界面的会酷点,选择了GTK这个GUI库。
因为我是想在我的windows上使用GTK库,结合我的visual studio2019一起使用,有一点了解的朋友们应该知道,gtk主要就是用在linux上,所以在windows上搞真的问题多多,在网上搜了很多,也没有一个能教在visual studio2019 windows环境下配置GTK的,真的太不容易了。
等过些天我有时间了,会将下面的代码都加上注释,并且配上运行效果图,也会写一篇在visual studio 2019 windows环境下配置GTK的博客,也会记录我使用GTK做软工大作业的过程,有兴趣的朋友可以继续关注我噢!⭐
后续:
windows+visualstudio2019配置GTK3教程
1. 介绍
是一款纯C的GUI库,简单、强大,Flat API,不需要面向对象的知识,用纯面向过程编写代码。
2. 测试代码
#include <gtk/gtk.h>
int main(int argc, char* argv[]) {
GtkWidget* window;
GtkWidget* label;
gtk_init(&argc, &argv);
/* create the main, top level, window */
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
/* give it the title */
gtk_window_set_title(GTK_WINDOW(window), "Hello World");
/* Connect the destroy signal of the window to gtk_main_quit
* When the window is about to be destroyed we get a notification and
* stop the main GTK+ loop
*/
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
/* Create the "Hello, World" label */
label = gtk_label_new("Hello, World");
/* and insert it into the main window */
gtk_container_add(GTK_CONTAINER(window), label);
/* make sure that everything, window and label, are visible */
gtk_widget_show_all(window);
/* start the main loop, and let it rest there until the application is closed */
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属性的值。
3.2 文本框、按钮和标签
-
文本框(GtkEntry)
#include <gtk/gtk.h> 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 <gtk/gtk.h> 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 <gtk/gtk.h> 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; }
3.3 盒子布局(GtkBox)
-
window中最多只能有一个子控件,一般窗口都有很多子控件,怎么办?
答:使用容器控件。window中放容器控件,其他控件都放容器控件中。
-
使用:
#include <gtk/gtk.h> 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; }
3.4 网格布局(GtkGrid)
#include <gtk/gtk.h>
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;
}
4. GTK深入
4.1 使用信号获得按钮点击消息
#include <gtk/gtk.h>
#include <stdio.h>
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_main_quit();*/
gtk_window_set_title(GTK_WINDOW(window), _2("小陌白"));
return 0;
}
4.2 复选按钮GtkCheckButton
#include <gtk/gtk.h>
#include <stdio.h>
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("男"));
/*gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cb1), true);*/
// 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;
}
4.3 单选按钮GtkRadioButton
#include <gtk/gtk.h>
#include <stdio.h>
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;
}
4.4 Label和Entry的更多函数
#include <gtk/gtk.h>
#include <stdio.h>
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;
}
4.5 下拉选择框GtkComboBoxText
#include <gtk/gtk.h>
#include <stdio.h>
#include <string.h>
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;
}
- 省市选择器
#include <gtk/gtk.h>
#include <stdio.h>
#include <string.h>
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;
}
4.6 工具栏GtkToolBar
#include <gtk/gtk.h>
#include <stdio.h>
#include <string.h>
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;
}