十七、Gtk4-Menu and action

news2025/1/12 12:24:30

Menu

用户经常使用菜单向计算机发出命令。它是这样的:
在这里插入图片描述现在让我们分析一下上面的菜单。对象有两种类型。

  • “File”, “Edit”, “View”, “Cut”, “Copy”, “Paste” and “Select All”. 它们被称为“菜单项(menu item)”或简单地称为“item”。当用户单击其中一项时,就会发生一些事情。
  • Menubar,submenu它们被称为“菜单”。Menu是一个有序的item列表。它们类似于数组。
    在这里插入图片描述
  • 菜单栏(Menubar)是一个包含 “File”, “Edit” 和 "View"三项的菜单。
  • 标签为“Edit”的菜单项有一个链接到包含两个项目的子菜单。这两项没有标签。每一项都代表一个section。
  • 第一部分是一个菜单,包含"Cut", “Copy” and "Paste"三个项目。
  • 第二部分是一个菜单,其中有一个项目——“Select All”。

由于菜单项之间的链接,菜单的结构很复杂。

GMenuModel, GMenu and GMenuItem

GMenuModel是一个表示菜单的抽象对象。GMenu是GMenuModel的一个简单实现,也是GMenuModel的一个子对象。

GObject – GMenuModel – GMenu

因为GMenuModel是一个抽象对象,它是不可实例化的。因此,它没有任何函数来创建它的实例。如果要创建一个菜单,使用g_menu_new创建一个GMenu实例。GMenu继承了GMenuModel的所有函数。

GMenuItem是一个直接派生自GObject的对象。GMenuItem和Gmenu(或者GMenuModel)没有父子关系。

GObject – GMenuModel – GMenu
GObject – GMenuItem

GMenuItem有属性。其中一个属性是label。例如,在第一个图中有一个菜单项(menu item)具有“Edit”标签。“Cut”、“Copy”、“Paste”和“Select All”也是菜单项的标签。其他属性将在后面解释。

一些菜单项有一个链接到另一个GMenu。有两种类型的链接,submenu 和 section。

GMenuItem可以被插入、添加或添加到GMenu中。当它被插入时,所有的属性和链接值都会被复制并存储在菜单中。GMenuItem本身并没有真正插入。因此,在插入之后,GMenuItem是无用的,它应该被释放。appending或prepending也是如此。

下面的代码展示了如何将GMenuItem追加到GMenu。

GMenu *menu = g_menu_new ();
GMenuItem *menu_item_quit = g_menu_item_new ("Quit", "app.quit");
g_menu_append_item (menu, menu_item_quit);
g_object_unref (menu_item_quit);

Menu and action

菜单项的一个属性是一个action。这个属性指向一个action对象。

有两个action对象,GSimpleAction和GPropertyAction。通常使用GSimpleAction。它与菜单项一起使用。本节只描述GSimpleAction。

当单击菜单项时,对应于菜单项的操作(action)将被激活。然后这个动作会发出一个激活信号。

  • 单击菜单项。
  • 相应的操作被激活。
  • 这个action发出一个信号。
  • 调用连接的处理程序。

下面的代码是一个示例。

static void
quit_activated(GSimpleAction *action, GVariant *parameter, gpointer app) { ... ... ...}

GSimpleAction *act_quit = g_simple_action_new ("quit", NULL);
g_action_map_add_action (G_ACTION_MAP (app), G_ACTION (act_quit));
g_signal_connect (act_quit, "activate", G_CALLBACK (quit_activated), app);
GMenuItem *menu_item_quit = g_menu_item_new ("Quit", "app.quit");
  • 变量menu_item_quit指向一个菜单项。它实际上是一个指针,但我们经常说menu_item_quit是一个菜单项。它有一个标签“Quit”,并连接到一个操作“app.quit”。"app"是前缀,"quit"是操作的名称。前缀“app”表示操作属于GtkApplication实例。
  • act_quit是一个动作。它有个名字叫“quit”。函数g_simple_action_new创建一个无状态的动作(stateless action)。因此,act_quit是无状态的。无状态的含义将在后面解释。实参NULL表示操作没有参数。大多数操作都是无状态的,也没有参数。
  • 动作act_quit通过g_action_map_add_action添加到GtkApplication实例。因此,动作的作用域是应用程序。app.quit的前缀表示作用域。
  • 该操作的"activate"信号连接到处理程序quit_activated。

如果点击菜单,则激活相应的动作“quit”,并发出“activate”信号。然后,调用处理程序quit_activated。

Menu bar

菜单栏和菜单都是传统风格的。菜单按钮最近经常被用来代替菜单栏,但旧的风格仍然被广泛使用。

应用程序只有一个菜单栏。如果一个应用程序有两个或多个具有菜单栏的窗口,则菜单栏是完全相同的。因为应用程序中的每个窗口都指向同一个菜单栏实例。

应用程序的菜单栏一旦设置好,通常不会改变。因此,在startup处理程序中设置它是合适的。因为它只在主应用程序实例中被调用一次。

我认为这对读者阐明应用程序的行为是有好处的。

  • 当应用程序第一次运行时,该实例称为主实例。
  • 主实例将自己注册到系统。如果成功,它会发出“startup”信号。
  • 当实例被激活时,会发出“activate”或“open”信号。
  • 如果应用程序第二次或以后运行,并且存在一个主实例,则该实例称为远程实例(remote instance)。
  • 远程实例不会发出“startup”信号。
  • 如果它试图发出“activate”或“open”信号,信号不会在远程 - 实例上发出,而是在主实例上发出。
  • 远程实例退出。

因此,“activate”或“open”处理程序可以被调用两次或多次。另一方面,“startup”处理程序只会被调用一次。因此,设置菜单栏应该在“startup”处理程序中完成。

static void
app_startup (GApplication *app) {
... ... ...
  gtk_application_set_menubar (GTK_APPLICATION (app), G_MENU_MODEL (menubar));
... ... ...
}

Simple example

下面是一个简单的菜单menu和操作action的例子。源文件menu1.c位于src/menu目录下。

 1 #include <gtk/gtk.h>
 2 
 3 static void
 4 quit_activated(GSimpleAction *action, GVariant *parameter, GApplication *application) {
 5   g_application_quit (application);
 6 }
 7 
 8 static void
 9 app_activate (GApplication *application) {
10   GtkApplication *app = GTK_APPLICATION (application);
11   GtkWidget *win = gtk_application_window_new (GTK_APPLICATION (app));
12   gtk_window_set_title (GTK_WINDOW (win), "menu1");
13   gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
14 
15   gtk_application_window_set_show_menubar (GTK_APPLICATION_WINDOW (win), TRUE);
16   gtk_window_present (GTK_WINDOW (win));
17 }
18 
19 static void
20 app_startup (GApplication *application) {
21   GtkApplication *app = GTK_APPLICATION (application);
22 
23   GSimpleAction *act_quit = g_simple_action_new ("quit", NULL);
24   g_action_map_add_action (G_ACTION_MAP (app), G_ACTION (act_quit));
25   g_signal_connect (act_quit, "activate", G_CALLBACK (quit_activated), application);
26 
27   GMenu *menubar = g_menu_new ();
28   GMenuItem *menu_item_menu = g_menu_item_new ("Menu", NULL);
29   GMenu *menu = g_menu_new ();
30   GMenuItem *menu_item_quit = g_menu_item_new ("Quit", "app.quit");
31   g_menu_append_item (menu, menu_item_quit);
32   g_object_unref (menu_item_quit);
33   g_menu_item_set_submenu (menu_item_menu, G_MENU_MODEL (menu));
34   g_menu_append_item (menubar, menu_item_menu);
35   g_object_unref (menu_item_menu);
36 
37   gtk_application_set_menubar (GTK_APPLICATION (app), G_MENU_MODEL (menubar));
38 }
39 
40 #define APPLICATION_ID "com.github.ToshioCP.menu1"
41 
42 int
43 main (int argc, char **argv) {
44   GtkApplication *app;
45   int stat;
46 
47   app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS);
48   g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL);
49   g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
50 
51   stat =g_application_run (G_APPLICATION (app), argc, argv);
52   g_object_unref (app);
53   return stat;
54 }
55 
  • 3-6: quit_activated是动作act_quit的“activate”信号处理程序。“activate”信号的处理程序有三个参数。
    • 发出信号的action实例。
    • 参数。在这个例子中,它是NULL,因为g_simple_action_new(第23行)的第二个参数是NULL。你不需要关心它。
    • 用户数据。这是g_signal_connect(第25行)中连接操作和处理程序的第四个参数。
  • 5:函数g_application_quit立即退出应用。
  • 8-17: app_activate是一个“激活”信号处理程序。
  • 11-13:创建一个GtkApplicationWindow窗口。并设置标题和默认大小。
  • 15: 设置GtkApplicationWindow显示菜单栏。
  • 16:显示窗口。
  • 19-38: app_startup是一个“启动”信号处理器
  • 23:创建GSimpleAction act_quit。它是无状态的。g_simple_action_new的第一个参数是动作的名称,第二个参数是一个形参。如果你不需要这个参数,就传递NULL。因此,act_quit有一个名字"quit",没有参数。
  • 24:在GtkApplication app中增加action。GtkApplication实现接口GActionMap和GActionGroup。GtkApplication (GActionMap)可以有一组动作,这些动作是用函数g_action_map_add_action添加的。该函数在Gio API参考——g_action_map_add_action中描述。因为这个动作属于GtkApplication,所以它的作用域是"app",如果需要前缀(作用域),它会通过"app.quit"进行使用。
  • 25:连接操作的“activate”信号和处理程序quit_activated
  • 27-30:创建GMenu和GMenuItem实例。menubar和menu是GMenu。menu_item_menu和menu_item_quit是GMenuItem。menu_item_menu只有一个“Menu”标签,没有任何操作。menu_item_quit有一个标签"Quit"和一个操作"app.quit"。
  • 31-32:将menu_item_quit添加到menu。正如我之前提到的,所有的属性和链接都被复制并用于在menu中形成一个新项目。因此,添加menu_item_quit之后,就不再需要menu_item_quit了。它由g_object_unref释放。
  • 33:将menu_item_menu中的子菜单链接设置为指向菜单。
  • 34-35:将menu_item_menu添加到menubar。然后释放menu_item_menu。将GMenu和GMenuItem连接起来,最终组成一个菜单。菜单的结构如下图所示。
  • 37:菜单栏插入到应用程序中。
    在这里插入图片描述

Compiling

将当前目录更改为src/menu。使用comp编译menu1.c。

$ comp menu1
$ ./a.out

然后,出现一个窗口。点击菜单栏上的“Menu”,就会出现一个菜单。点击“退出”菜单,应用程序退出。
在这里插入图片描述

Primary and remote application instances

让我们试着运行应用程序两次。在shell命令行中使用&,应用程序将并发运行。

然后,出现了两个窗口。

  • 第一个./out调用应用程序并创建一个主实例。它调用“startup”和“activate”处理程序并显示一个窗口。
  • 第二个./out再次调用应用程序,并且创建的实例是一个远程实例。它不会发出“启动”信号。它激活了应用程序,但“activate”信号是在主实例上发出的。远程实例退出。
  • 主实例称为activate处理程序。处理程序创建一个新窗口。它使用gtk_application_window_set_show_menubar函数向窗口添加一个菜单栏。

两个窗口都有菜单栏。它们完全一样。这两个窗口属于主实例。

如果单击“Quit”菜单,应用程序(主实例)将退出。
在这里插入图片描述
第二次运行创建了一个新窗口。然而,这取决于activate处理程序。如果在startup处理程序中创建窗口,activate处理程序只是显示窗口,那么在第二次运行时不会创建新窗口。例如,tfe(文本文件编辑器)不会创建第二个窗口。它只是创建了一个新的notebook页面。因为它的activate处理程序不创建任何窗口,而只是创建一个新的notebook页面。

在桌面应用程序上经常发生第二次或更多的执行。如果双击图标两次或两次以上,应用程序将运行多次。因此,你需要仔细考虑startup和activate (open)处理程序。

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

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

相关文章

字节青训前端笔记 | 前端调试

在程序员的世界中&#xff0c;BUG 一词相信同学们再熟悉不过了&#xff0c;本节课将围绕前端开发中所遇见的 BUG 出发&#xff0c;讲解作为一名合格的前端开发人员&#xff0c;你应该掌握哪些开发调试知识 Chorme DevTools Chorme DevTools 是 chorme内核为大家提供的高效的前…

gdb使用

gdb是一款UNIX及UNIX-like下的调试工具 gdb可用于调试用gcc编译的可执行文件&#xff0c;用gdb调试时gcc编译需要使用参数-g 本文是对于gdb在Linux下使用的基本命令的总结gdb调试视频演示&#xff0c;gdb调试基础指令&#xff0c;gdb调试其他命令&#xff0c;gdb常见错误说明 目…

23种设计模式(二十一)——命令模式【行为变化】

文章目录 意图什么时候使用命令真实世界类比命令模式的实现命令模式的优缺点亦称:动作、事务、Action、Transaction、Command 意图 将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。这样两者之间通过命令对象进行沟通,这样方便将命令对象进行储存、传递…

Centos7 Docker安装APISIX

Centos7 Docker安装APISIX1 基础介绍1.1 概念1.2 特性1.3 架构图2 快速安装2.1 前提条件2.2 安装步骤2.2.1 git命令克隆apisix-docker仓库2.2.2 docker-compose启动apisix2.2.3 访问apisix dashboard3 简单使用3.1 准备接口3.2 创建服务3.3 创建路由3.4 测试请求1 基础介绍 1.…

Kubernetes:分享一个很简洁的 k8s 管理工具 Skooner

写在前面 博文内容为 Skooner 简单介绍包括下载安装导入集群基本功能使用Skooner 的 sa 使用的当前命名空间默认的 sa不会显示创建 sa ,当然可以单独创建理解不足小伙伴帮忙指正 我所渴求的&#xff0c;無非是將心中脫穎語出的本性付諸生活&#xff0c;為何竟如此艱難呢 -----…

Spring_FrameWork_10(MyBatisPlus)

lombok mybatis:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImplTestvoid selectById(){IPage page new Page(2,2);bookDao.selectPage(page,null);System.out.println("当前页码值&#xff1a;"page.getCurrent());System.out.println…

Java---微服务---Nacos集群搭建

Nacos集群搭建1.集群结构图2.搭建集群2.1.初始化数据库2.2.下载nacos2.3.配置Nacos2.4.启动2.5.nginx反向代理2.6.优化1.集群结构图 官方给出的Nacos集群图&#xff1a; 其中包含3个nacos节点&#xff0c;然后一个负载均衡器代理3个Nacos。这里负载均衡器可以使用nginx。 我们…

解锁Windows所有电源选项

20230123 By wdhuag 目录 参考&#xff1a; 查看当前选项&#xff1a; 警告&#xff01;修改前&#xff0c;先使用Registry Workshop备份注册表&#xff0c;导出PowerSettings&#xff1a; 在PowerSettings里增加Attributes参数&#xff08;十六进制、数值2&#xff09;&a…

Shell脚本从入门到实战

Shell 文章目录Shellshell概述Shell脚本入门1. 脚本格式2. 第一个Shell脚本:helloworld3. 第二个Shell脚本&#xff1a;多命令处理Shell中的变量系统变量1. 常用系统变量2. 案例实操自定义变量1. 基本语法2. 变量定义规则特殊变量&#xff1a;$n特殊变量&#xff1a;$#特殊变量…

零基础学JavaWeb开发(二十二)之 springmvc入门到精通

一、SpringMVC概述 1、三层架构与MVC架构区别 1.1、三层架构 表示层&#xff1a;主要对用户的请求接受&#xff0c;以及数据的返回&#xff0c;为客户端提供应用程序的访问。 servlet层 业务逻辑层&#xff1a;对我们数据实现业务逻辑的封装 service层 数据访问层&#xf…

【Java|golang】2303. 计算应缴税款总额

给你一个下标从 0 开始的二维整数数组 brackets &#xff0c;其中 brackets[i] [upperi, percenti] &#xff0c;表示第 i 个税级的上限是 upperi &#xff0c;征收的税率为 percenti 。税级按上限 从低到高排序&#xff08;在满足 0 < i < brackets.length 的前提下&am…

【JavaScript】多态(Symbol),迭代器接口,getter/setter

❤️ Author&#xff1a; 老九 ☕️ 个人博客&#xff1a;老九的CSDN博客 &#x1f64f; 个人名言&#xff1a;不可控之事 乐观面对 &#x1f60d; 系列专栏&#xff1a; 文章目录多态symbol迭代器接口实现数组的迭代器方法练习Getter/Setter多态 我拿到一个对象&#xff0c;这…

【JavaScript】正则表达式详解

&#x1f4bb;【JavaScript】正则表达式&#x1f3e0;专栏&#xff1a;JavaScript &#x1f440;个人主页&#xff1a;繁星学编程&#x1f341; &#x1f9d1;个人简介&#xff1a;一个不断提高自我的平凡人&#x1f680; &#x1f50a;分享方向&#xff1a;目前主攻前端&#…

MySQL(五):事务简介、事务的特性、事务的概念及状态、支持事务的引擎

目录一、事务的起源二、事务的特性2.1 原子性(Atomicity)2.2 隔离性(Isolation)2.3 一致性(Consistency)2.4 持久性(Durability)三、事务的概念及状态四、支持事务的引擎一、事务的起源 事务源于日常生活中的业务&#xff0c;现有这样的一个场景&#xff0c;A账户有11元&#…

人工智能学习06--pytorch04--transforms

transforms主要对图片进行一些变换 transform该如何使用&#xff08;python&#xff09; 从transform中选择一个class&#xff0c;进行创建 依据创建的工具看需要什么&#xff08;如img&#xff09; 为什么需要tensor的数据类型 tensor数据类型&#xff1a;包装了神经网络…

opencv win10 4.7.0 源码编译 vs2019 cmake

下载opencv & opencv-contrib 4.7.0源码&#xff1b;注意下载地址https://github.com/opencv/opencv/releases https://github.com/opencv/opencv_contrib/releases/tag/4.7.0 版本要一模一样cmake输出文件夹为&#xff1a;opencv-4.7.0-build 遇到下载问题如下&#xf…

常见递归模式

常见递归模式递归模式遍历二叉树模式回溯模式子问题分解模式递归模式 常见递归模式&#xff1a; 遍历二叉树模式回溯模式子问题分解模式 遍历二叉树模式 只要涉及递归的问题&#xff0c;都是树的问题&#xff0c;或者说树的遍历。 void traverse(TreeNode root) { // 遍历…

混合背包问题

混合背包问题一、问题二、分析三、代码一、问题 二、分析 混合背包问题就是将我们之前讲过的01背包&#xff0c;完全背包&#xff0c;分组背包&#xff0c;多重背包问题等等中的任意几个混合在一起。因此想要解决这个问题&#xff0c;就需要对01背包&#xff0c;完全背包&…

PDF划词翻译软件

PDF划词翻译 一个简单的PDF划词翻译软件。 Github仓库地址&#xff1a;https://github.com/WCX1024979076/simple_pdf_translator Github下载地址&#xff1a; https://github.com/WCX1024979076/simple_pdf_translator/releases/tag/v0.1.0 Gitee仓库地址&#xff1a; htt…

ROS2机器人编程简述humble-第三章-COMPUTATION GRAPH .2

ROS2机器人编程简述humble-第三章-PERCEPTION AND ACTUATION MODELS .1避开障碍物计算图如何呢&#xff1f;该应用程序的计算图非常简单&#xff1a;订阅激光主题的节点向机器人发布速度命令。控制逻辑解释&#xff1a;输入的感知信息并产生控制命令&#xff08;输出&#xff0…