GTK开发(二)控件和布局


文章目录

  • GTK开发(二)控件和布局
  • 前言
  • 一、控件
    • 1、控件介绍
    • 2、带按钮的窗口
    • 3、其他补充
  • 二、布局
    • 1.水平布局
    • 2.垂直布局
    • 3.标签文本
    • 4.表格布局
    • 5.设置背景图
  • 总结

前言

之前已经介绍个gtk,以及做一个窗口,下面接着学习gtk开发相关知识,有关控件和布局,进而做一个漂亮的页面。


一、控件

1、控件介绍

控件是对数据和方法的封装。控件有自己的属性和方法。属性是指控件的特征。方法是指控件的一些简单而可见的功能。
在GTK+中,控件大体上可以分为两类,容器控件和非容器控件;
非容器控件不可以容纳别的控件,包括诸如文字标签、图像、单行输入等图形界面编程中的最基本的元素
容器控件:它可以容纳别的控件,我们可以理解为盒子,盒子拿来装东西。容器控件又分为两类,一类只能容纳一个控件,如窗口,按钮;另一类能容纳多个控件,如布局控件。
前面我们写的空白窗口是能容纳一个控件的控件,现在我们要做的是,给这个窗口添加一个按钮。
首先,我们需要创建一个按钮,然后需要把按钮添加到窗口,接着,显示按钮控件。

需要的函数:
创建一个带文件的按钮:
GtkWidget* gtk_button_new_with_label(const gchar* label);
label:按钮上的字符串类型,gchar相当于C语言的char
返回值:按钮控件指针
获取按键上的文本
const gchar* gtk_button_get_label(GtkButton* button);
把控件包含在窗口中
void gtk_container_add(GtkContainer * container,GtkWidget* widget);
container:容纳控件的容器
widget:要添加的控件
显示控件:void gtk_widget_show(GtkWidget *widget);
widget:需要显示的控件

2、带按钮的窗口

有了前面的简介很容易创建一个带按钮的窗口

#include <gtk/gtk.h>
#include <stdio.h>//点击关闭键后不退出
int main(int argc, char *argv[]) //在做gtk的时候要将const删除
{//GTK的开发流程//环境的初始化gtk_init(&argc,&argv);//创建一个窗口的控件来显示//gtk_window_new () 创建新的窗口 返回类型 GtkWidget *;GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL);//控件类型  变量      创建新的窗口     顶置有边框GtkWidget* button = gtk_button_new_with_label("你好,Gtk!");gtk_container_add(GTK_CONTAINER(window),button);//显示这个窗口gtk_widget_show_all(window);//信号 ,当点击关闭时退出程序g_signal_connect(window,"destroy",G_CALLBACK(gtk_main_quit),NULL);//信号连接函数     谁发出的信号 发出的什么样的信号  回调函数(系统自己定义的退出函数) 回调函数的参数//主事件循环gtk_main(); return 0;
}

运行之后会发现按下按键后无功能;要想按钮实现功能就需要添加按钮信号,实现功能.这就用到信号函数:
g_signal_connect(谁发出的信号,发出的什么信号,回调函数G_CALLBACK,回调函数的参数)
窗口关闭:destroy,delete-event
按键:pressed,clicked

g_signal_connect(button,“pressed”,G_CALLBACK(自己定义),“gtk”);
//按钮的信号函数是有规则的,有模板的
void 函数名(GtkButton* button ,gpointer user_data); (void*–>使用强转)

#include <gtk/gtk.h>
#include <stdio.h>//按钮信号区
void haha(GtkButton* button,gpointer user_data);//点击关闭键后不退出
int main(int argc, char *argv[]) //在做gtk的时候要将const删除
{//GTK的开发流程//环境的初始化gtk_init(&argc,&argv);//创建一个窗口的控件来显示//gtk_window_new () 创建新的窗口 返回类型 GtkWidget *;GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL);//控件类型  变量      创建新的窗口     顶置有边框GtkWidget* button = gtk_button_new_with_label("请戳我!");gtk_container_add(GTK_CONTAINER(window),button);//显示这个窗口gtk_widget_show_all(window);//信号 ,当点击关闭时退出程序g_signal_connect(button,"pressed",G_CALLBACK(haha),"疼");g_signal_connect(window,"destroy",G_CALLBACK(gtk_main_quit),NULL);//信号连接函数     谁发出的信号 发出的什么样的信号  回调函数(系统自己定义的退出函数) 回调函数的参数//主事件循环gtk_main(); return 0;
}//gpointer -->void *
void haha(GtkButton* button,gpointer user_data)
{printf("%s\n",gtk_button_get_label(button));printf("%s\n",(char*)user_data);
}

结果看下图

3、其他补充

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)。

gtk_widget_show(button);// 显示按钮
gtk_widget_show(window);// 显示窗口
如果,窗口里有多个控件要显示,这样一个一个地显示就会比较麻烦,所以,我们用gtk_widget_show_all()显示所有的控件,里面需要传的是容纳控件的那个容器(这里为窗口)。这样,容器上的控件也会跟着显示。
gtk_widget_show_all(window);// 显示窗口上的所有控件

二、布局

如果想要窗口里添加几个控件,直接添加是不成功的,因为窗口只能容纳一个控件。这时就需要借助布局容器,先把布局容器添加到窗口里,再把需要添加的控件放在布局容器里。

布局容器的主要分类:水平布局( GtkHBox)、垂直布局(GtkVBox )、表格布局(GtkTable)、固定布局(GtkFixed )。

1.水平布局


这里是需要的函数

创建水平布局容器
GtkWidget*gtk_hbox_new(gboolean homogeneous, gint spacing);
homogeneous:容器内控件是否均衡排放(大小一致) TRUE表示均匀
spacing: 控件之间的间隔
添加控件到布局容器中
gtk_container_add(GtkContainer*container, GtkWidget *widget );

这有个例子

#include <gtk/gtk.h>
#include <stdio.h>//按钮信号区
void haha(GtkButton* button,gpointer user_data);int main(int argc, char *argv[]) //在做gtk的时候要将const删除
{gtk_init(&argc,&argv);GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL);GtkWidget* hbox = gtk_hbox_new(TRUE,20);//把布局放进windowgtk_container_add(GTK_CONTAINER(window),hbox);GtkWidget* button = gtk_button_new_with_label("别戳我!");gtk_container_add(GTK_CONTAINER(hbox),button);GtkWidget* button1 = gtk_button_new_with_label("请戳我!");gtk_container_add(GTK_CONTAINER(hbox),button1);gtk_widget_show_all(window);g_signal_connect(button,"pressed",G_CALLBACK(haha),"哈哈");g_signal_connect(button1,"pressed",G_CALLBACK(haha),"嘻嘻");g_signal_connect(window,"destroy",G_CALLBACK(gtk_main_quit),NULL);gtk_main(); return 0;
}void haha(GtkButton* button,gpointer user_data)
{//printf("%s\n",gtk_button_get_label(button));printf("%s\n",(char*)user_data);
}

看运行结果

2.垂直布局


需要用到的函数

创建垂直布局容器
GtkWidget*gtk_vbox_new(gboolean homogeneous, gint spacing);
homogeneous:容器内控件是否均衡排放(大小一致) TRUE表示均匀
spacing: 控件之间的间隔
添加控件到布局容器中
gtk_container_add(GtkContainer*container, GtkWidget *widget );

代码如下(示例):

#include <gtk/gtk.h>
#include <stdio.h>//按钮信号区
void haha(GtkButton* button,gpointer user_data);int main(int argc, char *argv[]) //在做gtk的时候要将const删除
{gtk_init(&argc,&argv);GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL);GtkWidget* vbox = gtk_vbox_new(TRUE,20);//把布局放进windowgtk_container_add(GTK_CONTAINER(window),vbox);GtkWidget* button = gtk_button_new_with_label("别戳我!");gtk_container_add(GTK_CONTAINER(vbox),button);GtkWidget* button1 = gtk_button_new_with_label("请戳我!");gtk_container_add(GTK_CONTAINER(vbox),button1);gtk_widget_show_all(window);g_signal_connect(button,"pressed",G_CALLBACK(haha),"哈哈");g_signal_connect(button1,"pressed",G_CALLBACK(haha),"嘻嘻");g_signal_connect(window,"destroy",G_CALLBACK(gtk_main_quit),NULL);gtk_main(); return 0;
}void haha(GtkButton* button,gpointer user_data)
{//printf("%s\n",gtk_button_get_label(button));printf("%s\n",(char*)user_data);
}

可以看出来,垂直布局跟水平布局用法都一样

3.标签文本

这里有一个小例子来熟悉标签文本,点击一次按钮次数加一

标签(label):
GtkWidget*  gtk_label_new(const gchar* text);
eg:
GtkWidget* label = gtk_label_new("当前已经点击了0次");
获取文本:
gtk_label_get_text(GtkLable *label);设置文本:
gtk_label_set_text(GtkLable* label,gchar * text);//将字符串格式化输入到一个新的字符串
char ch[100]=" ";
sprintf(ch,"你已经点击了我%d次",i);
#include <gtk/gtk.h>
#include <stdio.h>//全局变量
int i=0;
GtkWidget* label;//按钮信号区
void click_numb(GtkButton* button,gpointer user_data);int main(int argc, char *argv[]) //在做gtk的时候要将const删除
{gtk_init(&argc,&argv);GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL);GtkWidget* vbox = gtk_vbox_new(TRUE,20);//把布局放进windowgtk_container_add(GTK_CONTAINER(window),vbox);//设置标签label = gtk_label_new("你已经点击了我0次");gtk_container_add(GTK_CONTAINER(vbox),label);GtkWidget* button = gtk_button_new_with_label("请戳我!");gtk_container_add(GTK_CONTAINER(vbox),button);gtk_widget_show_all(window);g_signal_connect(button,"pressed",G_CALLBACK(click_numb),NULL);g_signal_connect(window,"destroy",G_CALLBACK(gtk_main_quit),NULL);gtk_main(); return 0;
}void click_numb(GtkButton* button,gpointer user_data)
{//设置一个值,让它每点击一次数值加一i++;//将i放入到一个字符串中,将字符串设置到labelchar ch[30]="";sprintf(ch,"你已经点击了我%d次",i);gtk_label_set_text(GTK_LABEL(label),ch);}

运行结果如下

4.表格布局

通过过一个登录录界面来认识表格布局

需要的函数:

创建表格布局容器
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: 被容纳控件
后四个参数为控件摆放的坐标

看个这图来了解表格布局摆放规则


下面开始实现界面

#include <gtk/gtk.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>//全局变量区
GtkWidget* label_yzm;
GtkWidget* entry_yzm;//生成验证码
void do_yzm();
void do_dl(GtkButton* button,gpointer user_data);
void do_fh(GtkButton* button,gpointer user_data);int main(int argc, char *argv[])
{gtk_init(&argc,&argv);GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL);//设置表格布局GtkWidget* table = gtk_table_new(5,3,TRUE);gtk_container_add(GTK_CONTAINER(window),table);GtkWidget* label = gtk_label_new("河南理工教务系统登录界面");gtk_table_attach_defaults(GTK_TABLE(table),label,0,3,0,1);GtkWidget* label_yhm = gtk_label_new("用户名:");gtk_table_attach_defaults(GTK_TABLE(table),label_yhm,0,1,1,2);GtkWidget* label_pswd= gtk_label_new("密码:");gtk_table_attach_defaults(GTK_TABLE(table),label_pswd,0,1,2,3);label_yzm = gtk_label_new("验证码:");gtk_table_attach_defaults(GTK_TABLE(table),label_yzm,0,1,3,4);//行编辑新建中函数没有参数GtkWidget* entry_yhm = gtk_entry_new();gtk_table_attach_defaults(GTK_TABLE(table),entry_yhm,1,3,1,2);GtkWidget* entry_pswd = gtk_entry_new();gtk_table_attach_defaults(GTK_TABLE(table),entry_pswd,1,3,2,3);entry_yzm = gtk_entry_new();gtk_table_attach_defaults(GTK_TABLE(table),entry_yzm,1,3,3,4);GtkWidget* btn_dl = gtk_button_new_with_label("登录");gtk_table_attach_defaults(GTK_TABLE(table),btn_dl,0,1,4,5);GtkWidget* btn_zc = gtk_button_new_with_label("注册");gtk_table_attach_defaults(GTK_TABLE(table),btn_zc,1,2,4,5);GtkWidget* btn_fh = gtk_button_new_with_label("返回");gtk_table_attach_defaults(GTK_TABLE(table),btn_fh,2,3,4,5);do_yzm();gtk_widget_show_all(window);g_signal_connect(btn_dl,"pressed",G_CALLBACK(do_dl),NULL);g_signal_connect(btn_fh,"pressed",G_CALLBACK(do_fh),NULL);g_signal_connect(window,"destroy",G_CALLBACK(gtk_main_quit),NULL);gtk_main(); return 0;
}void do_yzm()
{char yzm[5]="";srand(time(NULL));int i;for (i = 0; i < 4; ++i){yzm[i]=rand()%10+'0';}gtk_label_set_text(GTK_LABEL(label_yzm),yzm);
}//做登录验证
void do_dl(GtkButton* button,gpointer user_data)
{const char* yzm_old = gtk_label_get_text(GTK_LABEL(label_yzm));const char* yzm_new = gtk_entry_get_text(GTK_ENTRY(entry_yzm));if (strcmp(yzm_new,yzm_old) == 0){gtk_label_set_text(GTK_LABEL(label_yzm),"验证成功");}else{gtk_label_set_text(GTK_LABEL(label_yzm),"验证失败");}}void do_fh(GtkButton* button,gpointer user_data)
{gtk_label_set_text(GTK_LABEL(label_yzm),"");gtk_entry_set_text(GTK_ENTRY(entry_yzm),"");do_yzm();
}

效果图看下面

5.设置背景图

设置背景图:

void chang_background(GtkWidget *widget, int w, int h, const gchar *path)
{gtk_widget_set_app_paintable(widget, TRUE);        //以TRUE标准,设置APP允许窗口可以绘图gtk_widget_realize(widget);    /* 更改背景图时,图片会重叠* 这时要手动调用下面的函数,让窗口绘图区域失效,产生窗口重绘制事件(即 expose 事件)。*/gtk_widget_queue_draw(widget);//等待重绘制GdkPixbuf *src_pixbuf = gdk_pixbuf_new_from_file(path, NULL);    // 创建图片资源对象// w, h是指定图片的宽度和高度GdkPixbuf *dst_pixbuf = gdk_pixbuf_scale_simple(src_pixbuf, w, h, GDK_INTERP_BILINEAR);//修改并保存获取的图片GdkPixmap *pixmap = NULL;/* 创建pixmap图像; * NULL:不需要蒙版; * 123: 0~255,透明到不透明*/gdk_pixbuf_render_pixmap_and_mask(dst_pixbuf, &pixmap, NULL, 128);// 通过pixmap给widget设置一张背景图,最后一个参数必须为: FASLEgdk_window_set_back_pixmap(widget->window, pixmap, FALSE);// 释放资源g_object_unref(src_pixbuf);g_object_unref(dst_pixbuf);g_object_unref(pixmap);
}

这里给个拓展,给界面设置背景图,使用的时候只需要声明一下然后直接调用就行


总结

通过这篇文章,学习了gtk的一些常用控件和布局,这样你也能做出精美的界面了。

GTK开发(二)控件和布局相关推荐

  1. C#进行MapX二次开发之控件基本操作

    上篇介绍了MapX的部分基本使用代码,包括放大.缩小.缩放到初始大小(全图).平移.矩形选择.圆形选择.箭头.打开图层对话框 .打开ActiveX属性对话框 .添加符号等基本操作代码,本篇继续探讨一些 ...

  2. 【Qt开发笔记】Qt自定义控件开发与使用,自定义控件实现容器与控件内布局

    1.开发环境 Qt版本:Qt 4.8.7 编译器:MinGw 系统:Windows 2.创建Qt4自定义控件 创建一个Qt自定义控件工程. 工程名为Custom. 控件类取名Custom. 然后完成创 ...

  3. WPF 的内部世界(控件与布局)

    我一开始算是比较抵触WPF的,因为用的人少吗.感觉都是窗体应用能和Winform有什么区别.可是我错了,非常感谢我的讲师,给我推荐刘铁猛的<深入浅出WPF>,让我了解到了WPF的魅力--数 ...

  4. WPF 组态软件实现思路(WPF控件可视化布局)

    WPF 开源 组态软件实现思路(WPF控件可视化布局) 一.实现控件选中及自由拖动 二.实现控件对齐功能 三.实现对齐辅助线功能 四.实现框选功能 GitHub地址点此 请注意 属性编辑控件基于Dev ...

  5. HarmonyOS应用开发-基本控件

    感谢关注HarmonyOS,为了便于大家学习特将鸿蒙2.0基础教学内容整理如下: 1.HarmonyOS应用开发-视频播放 https://developer.huawei.com/consumer/ ...

  6. 安卓基本控件与布局的使用

    一.基本控件 在搭建 Android 界面中 有许多的控件给我们使用,有 TextView ,EditText , Button , ImageView 等等,正是有了这些控件,我们才能搭建出好看的界 ...

  7. 服务器控件开发——组合控件(5)

    组合控件, 顾名思义就是指由2 个或2 个以上的已存在的控件组合在一起, 协同工作从而完成新功能的新的服务器控件组合控件由于能 够重用已经存在控件的功能, 能够最大限度的提升我们的开发效率.组合控件就 ...

  8. Android 通过代码改变控件的布局方式

    在很多情况下当我们在xml中布局的方式并不能满足我们的要求,而这时我们就需要通过在代码中控制控件的布局 根据不同的条件来控制布局.首先来了解一下安卓中的一些单位 dip: device indepen ...

  9. [转]使用C#开发ActiveX控件

    前言 ActiveX控件以前也叫做OLE控件,它是微软IE支持的一种软件组件或对象,可以将其插入到Web页面中,实现在浏览器端执行动态程序功能,以增强浏览器端的动态处理能力.通常ActiveX控件都是 ...

  10. Android游戏开发系统控件-Dialog

    Android游戏开发系统控件-Dialog Dialog(对话框)在Android应用开发中经常用到,下面是学习<Android游戏编程从零开始>一书,关于Dialog的初步学习. 创建 ...

最新文章

  1. Py之Data Base:Python和数据库的那些嘻嘻哈哈事详细攻略
  2. zoj 2723 Semi-Prime
  3. h5 bootstrap 小程序模板_青浦区社群小程序模板
  4. 怎样让电脑速度变快_双11的笔记本电脑怎么买?哪些轻薄款的最好?
  5. Spring实战(六)自动装配的歧义性
  6. mysql replace substring 字符串截取处理
  7. 解决Chrome浏览器不能访问https网站的问题
  8. JavaScript-面向对象(构造函数,实例成员,静态成员)
  9. caffe---之scale层
  10. 内码输入法手机版下载_内码输入法
  11. mfc 配合directshow
  12. 车牌识别SDK原理分析
  13. sdut oj 2738 小鑫の日常系列故事(七)——小纸条
  14. 2019版本ppt如何导出论文所需300dpi像素以上的高清图片
  15. 视频流PS打包方式详解
  16. 基于深度卷积神经网络的人脸识别考勤系统-VGG-PYTHON-QT(1)
  17. XSY #2815 净空
  18. 瑞萨单片机boot程序中串口打印字符串乱码-问题记录
  19. 高压开关柜/环网箱局放在线监测设备(局部放电在线监测装置设备)的分类与选型
  20. Mac下chromedriver下载及安装详解

热门文章

  1. 【转】清华本科结业生两年的工作经历
  2. 单点漫延问题(水陆判断、洪水漫延、无权最小路径)
  3. mysql删除密码代码_mysql 用户新建、受权、删除。密码修改
  4. “CSIG 计算机视觉前沿 · 研讨会”于6月28日在百度举行
  5. 期权杠杆比率如何计算?
  6. 小故事大道理:一把小椅子
  7. 小故事大道理:送你四个生活启示
  8. 汇总:各类手游渠道特点及选择方法
  9. 如何创建强命名程序集(Strong Name Assembly)
  10. PD源码阅读系列:PD节点启动