三、Gtk4-Widgets(1)

news2024/11/23 8:13:00

1 GtkLavel,GtkButton and GtkBox

1.1 GtkLabel

在前一节中,我们创建了一个窗口并将其显示在屏幕上。现在我们进入下一个主题,在这个窗口中添加部件。最简单的部件是GtkLabel。它是一个包含文本的部件。

 1 #include <gtk/gtk.h>
 2 
 3 static void
 4 app_activate (GApplication *app) {
 5   GtkWidget *win;
 6   GtkWidget *lab;
 7 
 8   win = gtk_application_window_new (GTK_APPLICATION (app));
 9   gtk_window_set_title (GTK_WINDOW (win), "lb1");
10   gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
11 
12   lab = gtk_label_new ("Hello.");
13   gtk_window_set_child (GTK_WINDOW (win), lab);
14 
15   gtk_window_present (GTK_WINDOW (win));
16 }
17 
18 int
19 main (int argc, char **argv) {
20   GtkApplication *app;
21   int stat;
22 
23   app = gtk_application_new ("com.github.ToshioCP.lb1", G_APPLICATION_DEFAULT_FLAGS);
24   g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
25   stat =g_application_run (G_APPLICATION (app), argc, argv);
26   g_object_unref (app);
27   return stat;
28 }
29 

将这个程序保存到文件lb1.c中。然后编译并运行它。

$ comp lb1
$ . / a.out

将出现一个消息为“Hello.”的窗口。
在这里插入图片描述pr4.c和lb1.c之间只有很小的变化。程序差异有助于了解两个文件之间的差异。

$ cd misc; diff pr4.c lb1.c
4c4
< app_activate (GApplication *app, gpointer user_data) {
---
> app_activate (GApplication *app) {
5a6
>   GtkWidget *lab;
8c9
<   gtk_window_set_title (GTK_WINDOW (win), "pr4");
---
>   gtk_window_set_title (GTK_WINDOW (win), "lb1");
9a11,14
> 
>   lab = gtk_label_new ("Hello.");
>   gtk_window_set_child (GTK_WINDOW (win), lab);
> 
18c23
<   app = gtk_application_new ("com.github.ToshioCP.pr4", G_APPLICATION_DEFAULT_FLAGS);
---
>   app = gtk_application_new ("com.github.ToshioCP.lb1", G_APPLICATION_DEFAULT_FLAGS);

这告诉我们:

  • 信号处理程序app_activate没有user_data参数。如果g_signal_connect的第四个参数为NULL,可以省略user_data。
  • 增加了一个新的变量lab的定义。
  • 窗口的标题被更改。
  • 创建一个标签,并将其作为子窗口连接到window。

函数gtk_window_set_child (GTK_WINDOW (win), lab)使lab标签成为窗口win的一个子构件。小心些而已。子部件不同于子对象。对象具有父子关系,部件也具有父子关系。但这两种关系是完全不同的。不要困惑。在程序lb1.c中,lab是win的一个子构件。子构件总是位于屏幕上的父构件中。看这个窗口如何出现在屏幕上。应用程序窗口包含标签。

这个窗口win没有任何父类对象。我们将这样的窗口称为顶层窗口。一个应用程序可以有多个顶层窗口。

2 GtkButton

下一个构件是GtkButton。它在屏幕上显示一个带有标签或图标的按钮。在本小节中,我们将创建一个带有标签的按钮。当按钮被点击时,它会发出“clicked”信号。下面的程序展示了如何捕获信号并执行某些操作。

 1 #include <gtk/gtk.h>
 2 
 3 static void
 4 click_cb (GtkButton *btn) {
 5   g_print ("Clicked.\n");
 6 }
 7 
 8 static void
 9 app_activate (GApplication *app) {
10   GtkWidget *win;
11   GtkWidget *btn;
12 
13   win = gtk_application_window_new (GTK_APPLICATION (app));
14   gtk_window_set_title (GTK_WINDOW (win), "lb2");
15   gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
16 
17   btn = gtk_button_new_with_label ("Click me");
18   gtk_window_set_child (GTK_WINDOW (win), btn);
19   g_signal_connect (btn, "clicked", G_CALLBACK (click_cb), NULL);
20 
21   gtk_window_present (GTK_WINDOW (win));
22 }
23 
24 int
25 main (int argc, char **argv) {
26   GtkApplication *app;
27   int stat;
28 
29   app = gtk_application_new ("com.github.ToshioCP.lb2", G_APPLICATION_DEFAULT_FLAGS);
30   g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
31   stat =g_application_run (G_APPLICATION (app), argc, argv);
32   g_object_unref (app);
33   return stat;
34 }
35 

请看第17 ~ 19行。首先,它创建一个带有标签“Click me”的GtkButton实例btn。然后,将该按钮作为子窗口添加到窗口win中。最后,将按钮的“clicked”信号连接到处理程序click_cb。因此,如果单击btn,则调用函数click_cb。后缀“cb”的意思是“call back”。

将程序命名为lb2.c并保存。现在编译并运行它。

在这里插入图片描述
出现一个带有按钮的窗口。单击按钮(它是一个很大的按钮,可以在窗口中的任何地方单击),然后在终端上出现一个字符串"Clicked."。它显示处理程序是通过单击按钮被调用的。

我们可以确保捕获了单击的信号,并通过使用g_print调用处理程序。但是,使用g_print与GUI库GTK不协调。因此,我们将更改handler。下面的代码是lb3.c。

 1 static void
 2 click_cb (GtkButton *btn, GtkWindow *win) {
 3   gtk_window_destroy (win);
 4 }
 5 
 6 static void
 7 app_activate (GApplication *app) {
 8   GtkWidget *win;
 9   GtkWidget *btn;
10 
11   win = gtk_application_window_new (GTK_APPLICATION (app));
12   gtk_window_set_title (GTK_WINDOW (win), "lb3");
13   gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
14 
15   btn = gtk_button_new_with_label ("Close");
16   gtk_window_set_child (GTK_WINDOW (win), btn);
17   g_signal_connect (btn, "clicked", G_CALLBACK (click_cb), win);
18 
19   gtk_window_present (GTK_WINDOW (win));
20 }

lb2.c和lb3.c的不同之处如下:

$ cd misc; diff lb2.c lb3.c
4,5c4,5
< click_cb (GtkButton *btn) {
<   g_print ("Clicked.\n");
---
> click_cb (GtkButton *btn, GtkWindow *win) {
>   gtk_window_destroy (win);
14c14
<   gtk_window_set_title (GTK_WINDOW (win), "lb2");
---
>   gtk_window_set_title (GTK_WINDOW (win), "lb3");
17c17
<   btn = gtk_button_new_with_label ("Click me");
---
>   btn = gtk_button_new_with_label ("Close");
19c19
<   g_signal_connect (btn, "clicked", G_CALLBACK (click_cb), NULL);
---
>   g_signal_connect (btn, "clicked", G_CALLBACK (click_cb), win);
29c29
<   app = gtk_application_new ("com.github.ToshioCP.lb2", G_APPLICATION_DEFAULT_FLAGS);
---
>   app = gtk_application_new ("com.github.ToshioCP.lb3", G_APPLICATION_DEFAULT_FLAGS);
35d34
< 

修改如下:

  • 删除了lb2.c中的函数g_print,并插入了两行代码。
    • click_cb有第二个参数,来自第19行的g_signal_connect的第四个参数。需要注意的是,click_cb的第二个参数和g_signal_connect的第四个参数的类型是不同的。前者是GtkWindow *,后者是GtkWidget *。编译器不会出错,因为g_signal_connect使用了gpointer(指针的一般类型)。在这个程序中,win指向的实例是一个GtkApplicationWindow对象。它是GtkWindow和GtkWidget类的后代,所以GtkWindow *和GtkWidget *都是实例的正确类型。
    • gtk_destroy (win)销毁顶层窗口然后应用退出。
  • btn的标签由Click me变为Close
  • g_signal_connect的第四个参数从NULL改为win。

最重要的变化是g_signal_connect的第四个参数。在g_signal_connect的定义中,该参数被描述为“传递给处理程序的数据”。

3 GtkBox

GtkWindow和GtkApplicationWindow只能有一个子窗口。如果你想在一个窗口中添加两个或更多的部件,你需要一个容器部件。GtkBox是其中一个容器。它将两个或更多的子部件排列到一行或一列中。下面的过程展示了在窗口中添加两个按钮的方法。

  • 创建一个GtkApplicationWindow实例。
  • 创建一个GtkBox实例,并将其作为子窗口添加到GtkApplicationWindow中。
  • 创建一个GtkButton实例并将其附加到GtkBox。
  • 创建另一个GtkButton实例并将其附加到GtkBox。

在此之后,构件被连接为下图所示。
在这里插入图片描述
程序lb4.c如下:

 1 #include <gtk/gtk.h>
 2 
 3 static void
 4 click1_cb (GtkButton *btn) {
 5   const char *s;
 6 
 7   s = gtk_button_get_label (btn);
 8   if (g_strcmp0 (s, "Hello.") == 0)
 9     gtk_button_set_label (btn, "Good-bye.");
10   else
11     gtk_button_set_label (btn, "Hello.");
12 }
13 
14 static void
15 click2_cb (GtkButton *btn, GtkWindow *win) {
16   gtk_window_destroy (win);
17 }
18 
19 static void
20 app_activate (GApplication *app) {
21   GtkWidget *win;
22   GtkWidget *box;
23   GtkWidget *btn1;
24   GtkWidget *btn2;
25 
26   win = gtk_application_window_new (GTK_APPLICATION (app));
27   gtk_window_set_title (GTK_WINDOW (win), "lb4");
28   gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
29 
30   box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
31   gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
32   gtk_window_set_child (GTK_WINDOW (win), box);
33 
34   btn1 = gtk_button_new_with_label ("Hello.");
35   g_signal_connect (btn1, "clicked", G_CALLBACK (click1_cb), NULL);
36 
37   btn2 = gtk_button_new_with_label ("Close");
38   g_signal_connect (btn2, "clicked", G_CALLBACK (click2_cb), win);
39 
40   gtk_box_append (GTK_BOX (box), btn1);
41   gtk_box_append (GTK_BOX (box), btn2);
42 
43   gtk_window_present (GTK_WINDOW (win));
44 }
45 
46 int
47 main (int argc, char **argv) {
48   GtkApplication *app;
49   int stat;
50 
51   app = gtk_application_new ("com.github.ToshioCP.lb4", G_APPLICATION_DEFAULT_FLAGS);
52   g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
53   stat =g_application_run (G_APPLICATION (app), argc, argv);
54   g_object_unref (app);
55   return stat;
56 }

看看函数app_activate。

在创建GtkApplicationWindow实例之后,会创建一个GtkBox实例。

box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5);
gtk_box_set_homogeneous (GTK_BOX (box), TRUE);

第一个参数是垂直排列box里面的子构件。方向常量的定义如下:

GTK_ORIENTATION_VERTICAL:子构件垂直排列
GTK_ORIENTATION_HORIZONTAL:子构件水平排列

第二个参数是子构件之间的大小。长度的单位是像素。

下一个函数是用子构件填充box时,给它们相同的空间大小(均匀分布)。

之后,创建了两个按钮btn1和btn2,并设置了信号处理程序。然后,将这两个按钮添加到box中。

 1 static void
 2 click1_cb (GtkButton *btn) {
 3   const char *s;
 4 
 5   s = gtk_button_get_label (btn);
 6   if (g_strcmp0 (s, "Hello.") == 0)
 7     gtk_button_set_label (btn, "Good-bye.");
 8   else
 9     gtk_button_set_label (btn, "Hello.");
10 }

函数gtk_button_get_lable返回标签中的文本。字符串归按钮所有,你不能修改或释放它。const限定符对于字符串s是必要的。如果你改变了字符串,编译器会给你一个警告。

当您看到GTK 4 API引用时,始终需要小心使用const限定符。
在这里插入图片描述

对应于btn1的处理程序切换其标签。btn2对应的处理程序会销毁顶层窗口,然后应用退出。

参考:Gtk4-tutorial Widgets (1)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/144602.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

spark sql 执行流程

最近学习了spark sql执行流程&#xff0c;从网上搜到了大都是sql解析、analyzer、optimizer阶段、sparkplan阶段&#xff0c;但是我比较好奇的是&#xff0c;这几个阶段是怎么串起来的&#xff0c;于是花了好几天着重从源码层面看看了看具体实现&#xff0c;写了几点自己认为应…

聊聊Mybatis的缓存

Mybatis缓存是内存中的数据&#xff0c;主要是对数据库查询结果的保存&#xff0c;使用缓存的好处是避免频繁与数据库进行交互&#xff0c;提升查询的响应速度。 数据库缓存扩展 聊到Mybatis缓存。我们可以扩展聊一下MySQL缓存。MySQL缓存其实与Mybatis类似&#xff0c;在查询…

物联网架构实例—Ubuntu 安装MongoDB及完全卸载

1.安装1.1.导入公钥wget -qO - https://www.mongodb.org/static/pgp/server-4.4.asc | sudo apt-key add -如果收到指示gnupg未安装的错误&#xff0c;则可以先执行&#xff1a;sudo apt-get install gnupg然后再执行一次导入公钥命令&#xff1a;wget -qO - https://www.mongo…

React(coderwhy)- 08(Hooks)

认识和体验Hooks 为什么需要Hook? ◼ Hook 是 React 16.8 的新增特性&#xff0c;它可以让我们在不编写class的情况下使用state以及其他的React特性&#xff08;比如生命周期&#xff09;。 ◼ 我们先来思考一下class组件相对于函数式组件有什么优势&#xff1f;比较常见的是下…

Exynos_4412——IIC总线概述

目录 一、IIC总线概述 1.1IIC总线简介 1.2IIC总线通信过程 1.3IIC总线寻址方式 二、IIC总线信号实现 2.1起始信号与停止信号 2.2字节传送与应答 2.3同步信号 三、典型IIC时序 四、小作业 一、IIC总线概述 1.1IIC总线简介 IIC总线IIC总线是Philips公司在八十年代初推…

[VP]河南第十三届ICPC大学生程序竞赛 L.手动计算

前言 传送门 : 题意 : 给定两个椭圆 的方程 , 要求 求出椭圆并集的面积之和 思路 : 本题很显然是积分 或者 计算几何的问题 对于积分的做法, 无非就是根据积分公式求出第一象限的面积 之后拓展到后面四个象限。(奈何我懒, 连两个椭圆的焦点都不想求更别提后面的积分公式了)…

Git遇到冲突?解决也太简单了

程序员宝藏库&#xff1a;https://gitee.com/sharetech_lee/CS-Books-Store git冲突是开发过程中很难避免的&#xff0c;对很多git初学者来说也是比较有障碍和门槛的一部分知识。 我认为要想彻底理解一个问题&#xff0c;首先要清楚这个问题是怎么产生的&#xff0c;然后才可以…

大数据NiFi(八):NiFi集群页面的组件工具栏介绍

NiFi集群页面的组件工具栏介绍 一、处理器(Processor)

WebLogic-执行队列

一&#xff0c;Tuning the Application Server 二&#xff0c;执行队列 Using Work Managers to Optimize Scheduled WorkThis chapter describes how WebLogic Server 12.1.3 lets you configure how your application prioritizes the execution of its work using a Work Ma…

java实现pdf转word,解决个别排版错乱问题

项目中要实现客户上传完pdf&#xff0c;上传成功后直接就转成word格式的&#xff0c;之前网上一些免费的转出来的word大致还行&#xff0c;但是有些排版就错乱了&#xff0c;如下图:下面这个是用java改造后的&#xff0c;效果如下&#xff0c;排版整齐&#xff0c;和pdf中的格式…

[总结] DDPM Diffusion模型各阶段训练和采样过程方案细节和代码逻辑汇总

DDPM Diffusion模型训练和采样过程细节汇总算法回顾框架理解DDPM训练过程采样过程Text-guiled DDPM训练过程采样过程Null-text guiled DDPM训练过程采样过程项目代码训练过程![在这里插入图片描述](https://img-blog.csdnimg.cn/f6213f8e584b4142b0c5a016cd23b63a.png)采样过程…

c++ std::funciona代替函数指针——结合std::bind

一、介绍std::function std::function是函数模板类&#xff08;是一个类&#xff09;。包含在#include <functional> 中。以前没有这个类的时候&#xff0c;我们在想定义一个回调函数指针&#xff0c;非常的麻烦。我们通常这样的定义&#xff1a; typedef void&#x…

智能小便冲洗器行业市场运行态势及未来发展潜力分析

2023-2029年中国智能小便冲洗器行业市场运行态势及未来发展潜力报告报告编号&#xff1a;1690632免费目录下载&#xff1a;http://www.cninfo360.com/yjbg/jdhy/cwjd/20230105/1690632.html本报告著作权归博研咨询所有&#xff0c;未经书面许可&#xff0c;任何组织和个人不得以…

Python人工智能之人脸识别face_recognition安装

face_recognition 模块使用系统环境搭建 系统环境 Ubuntu / deepin操作系统Python 3.6pycharm 开发工具 开发环境配置&#xff0c;安装各种系统包 人脸检测基于dlib&#xff0c;dlib依赖Boost和cmake 在windows中如果要使用dlib还是比较麻烦的&#xff0c;如果想省时间可以在…

【关于Linux中----文件系统、inode、软硬链接和动静态库】

文章目录一、理解文件系统和inode二、硬链接与软链接三、动静态库3.1、静态库与动态库3.2、生成静态库3.3、生成动态库一、理解文件系统和inode 在我前几篇博客中谈到的有关文件的话题&#xff0c;它们统一指的都是打开的文件&#xff0c;那么在这里&#xff0c;我要谈一下没有…

Java基础之《netty(22)—netty编码解码机制》

一、编码和解码的基本介绍 1、编写网络应用程序时&#xff0c;因为数据在网络中传输的都是二进制字节码数据&#xff0c;在发数据时就需要编码&#xff0c;接收数据时就需要解码 2、codec&#xff08;编解码器&#xff09;的组成部分有两个&#xff1a;decoder&#xff08;解…

看小红书排行榜,解构热点背后的出圈密码

导语&#xff1a; 随着消费升级&#xff0c;新中式茶饮也悄然“起风了”&#xff0c;传统茶从老一辈人的茶杯里&#xff0c;通过创新再造&#xff0c;成为年轻人的社交“新”头好&#xff0c;其衍生的“围炉煮茶”更成为小红书平台的热门话题。高流量曝光之路背后&#xff0c;…

一个精美的登录界面原来是这样做的

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 秩沅 原创 收录于专栏 玩归玩闹归闹&#xff0c;别拿java开玩笑 —————————————————— ⭐相关文章⭐ -通过窗口看…

隐形纱窗行业市场经营管理及发展趋势研究分析

2023-2029年中国隐形纱窗行业市场经营管理及发展趋势研究报告报告编号&#xff1a;1690619本报告著作权归博研咨询所有&#xff0c;未经书面许可&#xff0c;任何组织和个人不得以任何形式复制、传播或输出中华人民共和国境外。任何未经授权使用本报告的相关商业行为都将违反《…

【操作系统】计算机内存管理

1.内存管理目标rom-ram &#xff08;1&#xff09;为啥要做内存管理 计算机不可能所以用户进程和系统所需要的全部程序和数据放入主存&#xff0c;所以操作系统必须对内存空间进行合理有效的分配内存管理功能 内存分配回收&#xff1a;主存储器&#xff08;物理内存&#xff…