十八、Gtk4-Stateful action

news2024/11/27 14:51:39

有些动作action有状态。状态的典型值是布尔值或字符串。但是,如果你愿意,也可以使用其他类型的状态。

具有状态的动作称为有状态的。

Stateful action without a paramete

有些菜单被称为切换菜单。例如,全屏菜单有一个状态,它有两个值——全屏和非全屏。每次单击菜单时,状态的值都会改变。一个动作对应全屏菜单也有一个状态。它的值为TRUE或FALSE,称为布尔值。TRUE表示全屏,FALSE表示非全屏。

下面是除信号处理程序之外实现全屏菜单的示例代码。稍后将介绍信号处理程序。

GSimpleAction *act_fullscreen = g_simple_action_new_stateful ("fullscreen",
                                NULL, g_variant_new_boolean (FALSE));
g_signal_connect (act_fullscreen, "change-state", G_CALLBACK (fullscreen_changed), win);
g_action_map_add_action (G_ACTION_MAP (win), G_ACTION (act_fullscreen));
... ... ...
GMenuItem *menu_item_fullscreen = g_menu_item_new ("Full Screen", "win.fullscreen");
  • act_fullscreen是一个GSimpleAction实例。它是用g_simple_action_new_stateful创建的。这个函数有三个参数。第一个参数"fullscreen"是操作的名称。第二个参数是形参类型。NULL表示操作没有参数。第三个参数是动作的初始状态。它是一个GVariant值。下一小节将解释GVariant。函数g_variant_new_boolean (FALSE)返回一个GVariant值,即布尔值FALSE。如果有两个或更多的顶层窗口,每个窗口都有自己的act_fullscreen操作。因此,操作的数量与窗口的数量相同。
  • 连接动作act_fullscreen和“change-state”信号处理程序fullscreen_changed。如果单击全屏菜单,则激活相应的动作act_fullscreen。但没有处理器连接到"激活"信号。然后,对于具有NULL参数类型(如act_fullscreen)的布尔声明的操作,默认行为是通过“change-state”信号切换它们。
  • 该操作被添加到GtkWindow win中。因此,行动的范围是 “win” – window。
  • menu_item_fullscreen是一个GMenuItem实例。有两个参数。第一个参数"Full Screen"是menu_item_fullscreen的标签。第二个参数是一个动作。动作“赢”。Fullscreen “前缀是"win”,操作名称是" Fullscreen "。前缀表示操作属于窗口。
1 static void
2 fullscreen_changed(GSimpleAction *action, GVariant *value, GtkWindow *win) {
3   if (g_variant_get_boolean (value))
4     gtk_window_maximize (win);
5   else
6     gtk_window_unmaximize (win);
7   g_simple_action_set_state (action, value);
8 }
  • fullscreen_changed处理程序有三个参数。第一个参数是发出“change-state”信号的动作。第二个参数是操作的新状态的值。第三个参数是一个用户数据,在g_signal_connect中设置。
  • 如果值是布尔类型且为TRUE,则最大化窗口;否则unmaximizes。
  • 用value设置操作的状态。注意:第二个参数是切换后的状态值,但在此阶段,操作的状态具有原始值。因此,您需要通过g_simple_action_set_state用新值设置状态。

你可以使用“activate”信号代替“change-state”信号,或者同时使用两种信号。但上面的方法是最简单也是最好的。

GVariant

GVarient可以包含布尔值、字符串或其他类型的值。例如,下面的程序将TRUE赋值给类型为GVariant的值。

GVariant *value = g_variant_new_boolean (TRUE);

另一个例子是:

GVariant *value2 = g_variant_new_string ("Hello");

value2是一个GVariant,它的值是字符串类型"Hello"。GVariant可以包含其他类型,如int16、int32、int64、double等。

如果你想获得原始值,可以使用g_variant_get系列函数。例如,可以使用g_variant_get_boolean获取布尔值。

gboolean bool = g_variant_get_boolean (value);

因为value被创建为布尔类型GVariant和TRUE value,所以bool等于TRUE。同样,你可以从value2中得到一个字符串

const char *str = g_variant_get_string (value2, NULL);

第二个形参是一个指向gsize类型变量的指针(gsize定义为unsigned long)。如果它不是NULL,那么字符串的长度将由函数设置。如果是NULL,什么都不会发生。返回的字符串str不能更改。

Stateful action with a parameter

另一个有状态操作的例子是与颜色选择菜单相对应的操作。例如,有三个菜单,每个菜单分别有红色、绿色和蓝色。它们确定GtkLabel部件的背景颜色。一个操作连接到三个菜单。这个动作有一个值为"red"、"green"或"blue"的状态。值是字符串。这些颜色作为参数提供给信号处理程序。

... ... ...
GSimpleAction *act_color = g_simple_action_new_stateful ("color",
                   g_variant_type_new("s"), g_variant_new_string ("red"));
GMenuItem *menu_item_red = g_menu_item_new ("Red", "app.color::red");
GMenuItem *menu_item_green = g_menu_item_new ("Green", "app.color::green");
GMenuItem *menu_item_blue = g_menu_item_new ("Blue", "app.color::blue");
g_signal_connect (act_color, "activate", G_CALLBACK (color_activated), NULL);
... ... ...
  • act_color是一个GSimpleAction实例。它是用g_simple_action_new_stateful创建的。这个函数有三个参数。第一个参数"color"是操作的名称。第二个参数是一个参数类型,它是GVariantType。g_variant_type_new(“s”)创建字符串类型GVariantType (G_VARIANT_TYPE_STRING)。第三个参数是动作的初始状态。它是一个GVariant。GVariantType将在下一小节中解释。函数g_variant_new_string (“red”)返回一个GVariant值,其字符串值为"red"。
  • menu_item_red是一个GMenuItem实例。有两个参数。第一个实参"Red"是menu_item_red的标签。第二个参数是一个详细的操作。它的前缀是"app",动作名称是"color",目标是"red"。Target作为参数发送给动作。menu_item_green和menu_item_blue也是如此。
  • 连接动作act_color和“activate”信号处理程序color_activated。如果单击三个菜单中的一个,则通过菜单给出的target(参数)激活动作act_color。

下面是“activate”信号处理程序。

static void
color_activated(GSimpleAction *action, GVariant *parameter) {
  char *color = g_strdup_printf ("label.lb {background-color: %s;}",
                                   g_variant_get_string (parameter, NULL));
  gtk_css_provider_load_from_data (provider, color, -1);
  g_free (color);
  g_action_change_state (G_ACTION (action), parameter);
}
  • 有三个参数。第一个参数是发出“activate”信号的动作。第二个参数是给动作的参数。它是由菜单指定的颜色。第三个参数被省略了,因为g_signal_connect的第四个参数是NULL。
  • color是由g_strdup_printf创建的CSS字符串。g_strdup_printf的参数与printf C标准函数相同。G_variant_get_string获取参数中包含的字符串。你不能改变或释放字符串。
  • 设置css提供程序的颜色。label.lb是一个选择器。lable是GtkLabel的节点名,lb是一个类。label.lb选择具有lb类的GtkLabel。例如,菜单有GtkLabel来显示它们的标签,但它们没有lb类。因此,CSS不会改变它们的背景颜色。 - {background-color %s}将背景色设置为from参数中的颜色。
  • 释放字符串color。
  • 通过g_action_change_state改变状态。

注意:如果您没有设置“activate”信号处理程序,信号将被转发到“change-state”信号。因此,你可以使用“change-state”信号而不是“activate”信号。看src/menu/menu2_change_state.c.

GVariantType

GVariantType给出GVariant的类型。GVariant可以包含多种类型。而且类型通常需要在运行时识别。

GVariantType由一个表示类型的字符串创建。

“b”表示布尔类型。
“s”表示字符串类型。

下面的程序是一个简单的例子。最后输出字符串"s"。

1 #include <glib.h>
2 
3 int
4 main (int argc, char **argv) {
5   GVariantType *vtype = g_variant_type_new ("s");
6   const char *type_string = g_variant_type_peek_string (vtype);
7   g_print ("%s\n",type_string);
8 }
  • g_variant_type_new创建GVariantType。它使用字符串类型“s”,表示字符串。
  • g_variant_type_peek_string查看了vtype。它是创建vtype时传给它的字符串"s"。
  • 将字符串打印到终端。

Example

下面的代码包含了上面的有状态操作。这个程序有这样的菜单:
在这里插入图片描述

  • 全屏菜单在最大和非最大窗口之间切换窗口大小。如果窗口是最大尺寸的,即fullscreen,则在fullscreen标签之前添加一个复选标记。
  • 红绿蓝菜单决定了任何标签的背景颜色。菜单的左侧有单选按钮。选中菜单的单选按钮打开。
  • 退出菜单退出应用程序。

代码如下。

  1 #include <gtk/gtk.h>
  2 
  3 /* The provider below provides application wide CSS data. */
  4 GtkCssProvider *provider;
  5 
  6 static void
  7 fullscreen_changed(GSimpleAction *action, GVariant *value, GtkWindow *win) {
  8   if (g_variant_get_boolean (value))
  9     gtk_window_maximize (win);
 10   else
 11     gtk_window_unmaximize (win);
 12   g_simple_action_set_state (action, value);
 13 }
 14 
 15 static void
 16 color_activated(GSimpleAction *action, GVariant *parameter) {
 17   char *color = g_strdup_printf ("label.lb {background-color: %s;}", g_variant_get_string (parameter, NULL));
 18   /* Change the CSS data in the provider. */
 19   /* Previous data is thrown away. */
 20   gtk_css_provider_load_from_data (provider, color, -1);
 21   g_free (color);
 22   g_action_change_state (G_ACTION (action), parameter);
 23 }
 24 
 25 static void
 26 remove_provider (GApplication *app, GtkCssProvider *provider) {
 27   GdkDisplay *display = gdk_display_get_default();
 28   
 29   gtk_style_context_remove_provider_for_display (display, GTK_STYLE_PROVIDER (provider));
 30   g_object_unref (provider);
 31 }
 32 
 33 static void
 34 app_activate (GApplication *app) {
 35   GtkWindow *win = GTK_WINDOW (gtk_application_window_new (GTK_APPLICATION (app)));
 36   gtk_window_set_title (win, "menu2");
 37   gtk_window_set_default_size (win, 400, 300);
 38 
 39   GtkWidget *lb = gtk_label_new (NULL);
 40   gtk_widget_add_css_class (lb, "lb"); /* the class is used by CSS Selector */
 41   gtk_window_set_child (win, lb);
 42 
 43   GSimpleAction *act_fullscreen
 44     = g_simple_action_new_stateful ("fullscreen", NULL, g_variant_new_boolean (FALSE));
 45   g_signal_connect (act_fullscreen, "change-state", G_CALLBACK (fullscreen_changed), win);
 46   g_action_map_add_action (G_ACTION_MAP (win), G_ACTION (act_fullscreen));
 47 
 48   gtk_application_window_set_show_menubar (GTK_APPLICATION_WINDOW (win), TRUE);
 49 
 50   gtk_window_present (win);
 51 }
 52 
 53 static void
 54 app_startup (GApplication *app) {
 55   GSimpleAction *act_color
 56     = g_simple_action_new_stateful ("color", g_variant_type_new("s"), g_variant_new_string ("red"));
 57   GSimpleAction *act_quit
 58     = g_simple_action_new ("quit", NULL);
 59   g_signal_connect (act_color, "activate", G_CALLBACK (color_activated), NULL);
 60   g_signal_connect_swapped (act_quit, "activate", G_CALLBACK (g_application_quit), app);
 61   g_action_map_add_action (G_ACTION_MAP (app), G_ACTION (act_color));
 62   g_action_map_add_action (G_ACTION_MAP (app), G_ACTION (act_quit));
 63 
 64   GMenu *menubar = g_menu_new ();
 65   GMenu *menu = g_menu_new ();
 66   GMenu *section1 = g_menu_new ();
 67   GMenu *section2 = g_menu_new ();
 68   GMenu *section3 = g_menu_new ();
 69   GMenuItem *menu_item_fullscreen = g_menu_item_new ("Full Screen", "win.fullscreen");
 70   GMenuItem *menu_item_red = g_menu_item_new ("Red", "app.color::red");
 71   GMenuItem *menu_item_green = g_menu_item_new ("Green", "app.color::green");
 72   GMenuItem *menu_item_blue = g_menu_item_new ("Blue", "app.color::blue");
 73   GMenuItem *menu_item_quit = g_menu_item_new ("Quit", "app.quit");
 74 
 75   g_menu_append_item (section1, menu_item_fullscreen);
 76   g_menu_append_item (section2, menu_item_red);
 77   g_menu_append_item (section2, menu_item_green);
 78   g_menu_append_item (section2, menu_item_blue);
 79   g_menu_append_item (section3, menu_item_quit);
 80   g_object_unref (menu_item_red);
 81   g_object_unref (menu_item_green);
 82   g_object_unref (menu_item_blue);
 83   g_object_unref (menu_item_fullscreen);
 84   g_object_unref (menu_item_quit);
 85 
 86   g_menu_append_section (menu, NULL, G_MENU_MODEL (section1));
 87   g_menu_append_section (menu, "Color", G_MENU_MODEL (section2));
 88   g_menu_append_section (menu, NULL, G_MENU_MODEL (section3));
 89   g_menu_append_submenu (menubar, "Menu", G_MENU_MODEL (menu));
 90 
 91   gtk_application_set_menubar (GTK_APPLICATION (app), G_MENU_MODEL (menubar));
 92 
 93   provider = gtk_css_provider_new ();
 94   /* Initialize the css data */
 95   gtk_css_provider_load_from_data (provider, "label.lb {background-color: red;}", -1);
 96   /* Add CSS to the default GdkDisplay. */
 97   GdkDisplay *display = gdk_display_get_default ();
 98   gtk_style_context_add_provider_for_display (display, GTK_STYLE_PROVIDER (provider),
 99                                               GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
100   g_signal_connect (app, "shutdown", G_CALLBACK (remove_provider), provider);
101 }
102 
103 #define APPLICATION_ID "com.github.ToshioCP.menu2"
104 
105 int
106 main (int argc, char **argv) {
107   GtkApplication *app;
108   int stat;
109 
110   app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS);
111   g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL);
112   g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
113 
114   stat =g_application_run (G_APPLICATION (app), argc, argv);
115   g_object_unref (app);
116   return stat;
117 }
118 
  • 6-23:连接到操作的信号处理程序。
  • 25-31:当应用程序退出时调用处理程序remove_provider。它将提供程序从显示中移除并释放提供程序。
  • 33-51:激活信号处理程序。
  • 35-37:创建一个新窗口,并将其分配给win。它的标题和默认大小分别被设置为"menu2"和400x300。
  • 39-41:创建新的标签并分配给lb,名称为lb,与CSS中使用的名称相同。这是添加到win作为一个child。
  • 43-46:创建切换动作并将其分配给act_fullscreen。它连接到信号处理程序fullscreen_changed。它被添加到窗口中,所以作用域是“win”。操作对应于窗口。因此,如果有两个或更多窗口,则创建两个或更多操作。
  • 48:函数gtk_application_window_set_show_menubar向窗口添加一个菜单栏。
  • 50:显示窗口。
  • 53-101:启动信号处理程序。
  • 55-62:创建两个动作act_color和act_quit。这些操作只存在一个,因为启动处理程序被调用了一次。它们连接到它们的处理程序并添加到应用程序中。它们的作用域是“app”。
  • 64-89:构建菜单。
  • 91:菜单栏添加到应用程序中。
  • 93-100:创建css provider,设置数据并添加到默认显示。应用程序上的“shutdown”信号连接到处理程序“remove_provider”。因此,当应用程序退出时,提供程序将从显示中移除并释放。

Compile

将当前目录更改为src/menu。

$ comp menu2
$./a.out

然后,您将看到一个窗口,内容的背景色为红色。您可以将大小更改为最大,然后再更改为原始大小。您可以更改背景颜色为绿色或蓝色。

如果再次运行应用程序,同一个屏幕上会出现另一个窗口。两个窗口的背景颜色相同。因为act_color动作具有“app”作用域,并且CSS应用于由windows共享的默认显示。

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

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

相关文章

在甲骨文云容器实例(Container Instances)上部署edge

甲骨文云推出了容器实例&#xff0c;这是一项无服务器计算服务&#xff0c;可以即时运行容器&#xff0c;而无需管理任何服务器。 今天我们尝试一下通过容器实例部署edge。 Step1. 创建容器实例 在甲骨文容器实例页面&#xff0c;单击"创建容器实例"&#xff0c; …

审批工作流—ccflow

审批工作流—ccflow目录概述需求&#xff1a;设计思路实现思路分析1.java 代码分析参考资料和推荐阅读Survive by day and develop by night. talk for import biz , show your perfect code,full busy&#xff0c;skip hardness,make a better result,wait for change,challen…

LeetCode[547]省份数量

难度&#xff1a;中等题目&#xff1a;有 n个城市&#xff0c;其中一些彼此相连&#xff0c;另一些没有相连。如果城市 a与城市 b直接相连&#xff0c;且城市 b与城市 c直接相连&#xff0c;那么城市 a与城市 c间接相连。省份 是一组直接或间接相连的城市&#xff0c;组内不含其…

Leetcode:93. 复原 IP 地址(C++)

目录 问题描述&#xff1a; 实现代码与解析&#xff1a; 回溯&#xff1a; 原理思路&#xff1a; 问题描述&#xff1a; 有效 IP 地址 正好由四个整数&#xff08;每个整数位于 0 到 255 之间组成&#xff0c;且不能含有前导 0&#xff09;&#xff0c;整数之间用 . 分隔。…

leetcode刷题记录总结-2.链表

文章目录一、重排列表[1. 奇偶链表](https://leetcode.cn/problems/odd-even-linked-list/solutions/)题解二、链表的增、删、改、查[203. 移除链表元素](https://leetcode.cn/problems/remove-linked-list-elements/)题解不简洁代码简洁代码707.设计链表题解不简洁代码优化后的…

mysql主从复制配置(windows和linux操作都有)

我是目录主从复制是什么&#xff1f;操作实践验证主从设置主从复制是什么&#xff1f; mysql主从复制是一个异步的复制过程&#xff0c;底层是基于mysql数据库自带的二进制日志功能。就是一台或多台mysal数据库&#xff08;slave&#xff0c;即从库&#xff09;从另一台mysql数…

macOS Big Sur 11.7.3 (20G1116) 正式版 ISO、PKG、DMG、IPSW 下载

本站提供的 macOS Big Sur 软件包&#xff0c;既可以拖拽到 Applications&#xff08;应用程序&#xff09;下直接安装&#xff0c;也可以制作启动 U 盘安装&#xff0c;或者在虚拟机中启动安装。 请访问原文链接&#xff1a;https://sysin.org/blog/macOS-Big-Sur/&#xff0…

【Python百日进阶-Web开发-Linux】Day236 - Win11安装Windows Subsystem for Android(WSA)

文章目录一、Win11运行安卓app前提条件二、Win11运行安卓app支持以下新特性三、Win11运行安卓app操作步骤3.1 修改定位3.2 开启VT虚拟化3.3 开启电脑的Hyper-V和虚拟机平台四、WSA下载4.1 百度网盘下载4.2 store.rg-adguard.net下载五、WSA安装&#xff08;没有成功&#xff0c…

C++初阶--继承

目录 继承的概念 继承定义 继承基类成员访问方式 基类和派生类对象的赋值转换 继承中的作用域 派生类的默认成员函数 友元关系不能继承 基类static成员 菱形继承与菱形虚拟继承 虚拟继承解决数据冗余和二义性的原理 继承和组合 继承的概念 继承是类层次的复用。 继…

Golang 泛型学习

Golang 泛型 今天来学习下Golang中泛型的基础知识。使用泛型&#xff0c;开发者可以声明一个函数来适应不同类型的参数&#xff0c;避免由于参数类型不一致而声明多个处理逻辑类似的函数。在本教程中&#xff0c;将声明两个简单的非泛型函数&#xff0c;然后在单个泛型函数中实…

这些实体店直播必备技巧,新手直接套用就能火!

随着直播的受众越来越广、门槛越来越低&#xff0c;入局服装直播的实体店越来越多。对于服装厂商来说&#xff0c;服装产业链越靠下游毛利率越高&#xff0c;品牌商和销售商利润远高于加工生产商&#xff0c;约在40-50%&#xff0c;而服装制造商的毛利率仅在15%左右。而对于本土…

JDK8 新特性之收集Stream流中的结果

目录 一&#xff1a;Stream流中的结果到集合中 二&#xff1a;Stream流中的结果到数组中 三&#xff1a;对流中数据进行聚合计算 四&#xff1a;对流中数据进行分组 五&#xff1a;对流中数据进行多级分组 六&#xff1a;对流中数据进行分区 七&#xff1a;对流中数据进行拼接…

8.Java循环高级综合练习-无限循环和跳转控制语句,逢七过,平方根,判断是否为质数,猜数字小游戏

文章目录前言一、无限循环1.这三种循环中哪一种无限循环是最常用的呢?2.注意事项:二、跳转控制语句三、逢七过四、平方根五、判断该整数是否为一个质数六、猜数字小游戏保底机制总结前言 一、无限循环 1.这三种循环中哪一种无限循环是最常用的呢? 当然是右上角的while循环啦…

【若依】若依字典管理页面中列表按钮功能的实现

0. 功能实现描述 1. 代码实现 ScStfController.java /*** 查询员工证书* param stfId* param modelMap* return*/ RequiresPermissions("sc:stf:cert") GetMapping("/cert/{stfId}") public String detail(PathVariable("stfId") Long stfId, …

结构型模式-组合模式

1.概述 对于这个图片肯定会非常熟悉&#xff0c;上图我们可以看做是一个文件系统&#xff0c;对于这样的结构我们称之为树形结构。在树形结构中可以通过调用某个方法来遍历整个树&#xff0c;当我们找到某个叶子节点后&#xff0c;就可以对叶子节点进行相关的操作。可以将这颗树…

谷粒学院——Day19【项目部署】

❤ 作者主页&#xff1a;欢迎来到我的技术博客&#x1f60e; ❀ 个人介绍&#xff1a;大家好&#xff0c;本人热衷于Java后端开发&#xff0c;欢迎来交流学习哦&#xff01;(&#xffe3;▽&#xffe3;)~* &#x1f34a; 如果文章对您有帮助&#xff0c;记得关注、点赞、收藏、…

Java中的hashCode,真的很容易弄懂

写这篇文章是因为在看hashMap源码时遇到有什么hashcode值&#xff0c;然后就去查&#xff0c;脑袋里面是有印象的&#xff0c;不就是在Object中有equals和hashcode方法嘛&#xff0c;这在学java基础的时候就遇到过&#xff0c;不过那时候无所谓&#xff0c;囫囵吞枣&#xff0c…

三、python基础语法进阶篇(黑马程序猿-python学习记录)

黑马程序猿的python学习视频&#xff1a;https://www.bilibili.com/video/BV1qW4y1a7fU/ 目录 一、文件操作 一、 文件的读取 1. 打开文件open() 2. 读取文件10个字节read(10) 3. 读取文件全部信息read() 4. 读取文件readLines() 5. 读取文件readLine() 6. for循环读取…

Nginx与LUA(7)

您好&#xff0c;我是湘王&#xff0c;这是我的CSDN博客。值此新春佳节&#xff0c;我给您拜年啦&#xff5e;祝您在新的一年中所求皆所愿&#xff0c;所行皆坦途&#xff0c;展宏“兔”&#xff0c;有钱“兔”&#xff0c;多喜乐&#xff0c;常安宁&#xff01;软件开发中&…

使用小程序+网页简易实现多客户端实时弹幕

此文主要通过小程序网页模拟多客户端通过轮询、WebSockets、订阅推送等方式简易实现实时弹幕。 实现流程1、服务端1.1、创建项目2.2、接口定义2、客户端2.1、小程序端2.2、web端3、实现方式3.1、轮询3.2、WebSocket3.3、订阅推送实现流程 1、服务端 1.1、创建项目 打开Visual…