gtk3基础知识的学习(C语言)

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,会乱码。有以下两种解决方法:

  1. 将代码文件保存为utf-8无签名版(注意一定是无签名版)
  2. 使用我后面的代码,我封装好了函数调用,将中文字符串转为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;
}

  • 8
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小陌白

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值