修改 GTK 按钮样式/CSS 并立即更新/刷新

Posted

技术标签:

【中文标题】修改 GTK 按钮样式/CSS 并立即更新/刷新【英文标题】:Modify GTK button style / CSS and update/refresh instantly 【发布时间】:2020-10-22 13:04:51 【问题描述】:

让我先说我是 GTK Noob,发现自己被空降到修改别人的代码 - 其他人已经逃离这个国家到更环保的土地。

所以,我们有一个 GTK 按钮网格,它只是一个彩色方块,每个按钮都可以即时修改以改变颜色。

目前,程序流程是这样的;

生成包含 25 种按钮颜色样式列表的 CSS,如下所示:

.btn_colour_id_XXbackground: #336699
.btn_colour_id_XX:active background: shade(#336699, 0.5) 

然后根据我们想要的颜色为每个按钮附加一个样式:

GtkStyleContext *context = gtk_widget_get_style_context(button);
snprintf(value, 20, "btn_colour_id_%02d", colour_id); // Apply colour_id to button
gtk_style_context_add_class(context, value);

并显示我们的充满按钮的窗口。

当我们调用 modify 按钮颜色时,代码只是将该按钮的 CSS 样式切换为请求的样式:

snprintf(desired_class, 10, "btn_colour_id_%02d", color_id); // Style we want for button
for (GList *l = classes; l != NULL; l = l->next)

    char *classname = (char *)l->data;
    if (strstr(classname, "btn_colour_id_") == NULL)
    
        continue;
    
    if (strlen(classname) != strlen(desired_class) || strstr(classname, desired_class) == NULL)
    
        g_message("Swapping [%s] colour from %s > %s", name, classname, desired_class);
        gtk_style_context_remove_class(context, (const gchar *)l->data);
        gtk_style_context_add_class(context, desired_class);
    

但是,需要能够将 any 按钮设置为 any RGB 颜色 on-the-fly,而我我不相信创建 2^24 CSS 样式是最佳途径;)

我的想法是,我们改为为每个按钮提供其 自己的 CSS id 选择器和自己的 RGB 颜色,并根据需要简单地修改 CSS 中的颜色值......但是,我已经用谷歌搜索了一半死看着 GTK 文档,我看不到任何明显的方法可以修改 现有的 CSS 并将该更改反映在显示的按钮中。

谁能指出我正确的方向?


编辑:到目前为止,我已经找到了几个 potential examples...

这个……

static GtkCssProvider* provider = NULL;

static void set_label_color(GtkWidget* label, const char* color)

    const char* format = "label  color: %s; ";
    size_t length = strlen(format) - 2 + 1;
    char style[length];
    sprintf(style, format, color);

    if (provider == NULL) 
        // only create and add the provider the first time
        provider = gtk_css_provider_new();
        gtk_style_context_add_provider(
            gtk_widget_get_style_context(label),
            GTK_STYLE_PROVIDER(provider),
            GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
        g_object_unref(provider);
    

    gtk_css_provider_load_from_data(provider, style, -1, NULL);
 

还有这个……

void set_background_color(GtkWidget *w, gchar *color)

    GtkCssProvider *gcp;
    GtkStyleContext *gsc;
    gsc = gtk_widget_get_style_context(w);
    const gchar *type = g_type_name (G_TYPE_FROM_INSTANCE (w));
    gchar *str = g_strdup_printf ("%s background-color: %s;", type,
color);
    gcp= gtk_css_provider_new();
    gtk_css_provider_load_from_data(gcp, str, -1, 0);
    g_free (str);
    gtk_style_context_add_provider(gsc, GTK_STYLE_PROVIDER(gcp),
    GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);


// I don't know if there is a memory leak here though...

我也不确定其中任何一个是否存在内存泄漏,以及提供程序是静态的还是被破坏/在添加到小部件的上下文后是否可以释放()d...文档/示例似乎对此含糊其辞,任何人都有关于如何在应用程序中创建/管理多个提供者的不错的教程?

第一个示例对我来说看起来最有希望,尽管一遍又一遍地重写 provier 似乎有点粗糙?

【问题讨论】:

所以基本上只要你得到正确的 modify_color 信号,你只想修改 gtk_button 颜色到你的 25 种或更多颜色吗?还是你也在改变按钮样式? 我希望能够将任何单个按钮修改为 any RGB 颜色,而不是 1-of-25,而是 1-of-16777215。更广泛地说,只是能够在代码运行时修改 GTK CSS——感觉就像我为每个按钮分配了自己的 CSS ID 并在屏幕 CSS 中定义了样式,我应该能够只在飞,但我没有看到实现这一目标的直接方法,可能是因为我对 GTK 缺乏经验。 【参考方案1】:

好的,我自己想通了 - 这可能是完全错误的方法,但它确实有效。

它涉及将 CSS 提供程序(而不是使用后的 g_object_deref())保存在包含所有按钮信息的全局上下文中。然后每次都简单地覆盖 CSS 提供程序,TFM 说这非常好。

我们必须保留 CSS 提供程序和它的引用,因为 GTK 似乎缺少很多函数来从对象中获取此类信息添加新的、替换的和销毁/取消引用,但你不能读回现有的并修改它。我猜大多数 UI 都是你写一次就可以了。

上下文:

struct dev_button

    GtkWidget *btn;
    GtkCssProvider *bp;
;

创建按钮:

dbp = &_context->buttons[i]; // Pointer to a dev_button struct

GtkStyleContext *context = gtk_widget_get_style_context(dbp->btn);
dbp->bp = gtk_css_provider_new();
    
// Create a CSS for this button
snprintf(css, LONG_STR, ".btnid_%02dbackground: #%06X", btnID, colour);
        
// Convert CSS to provider
gtk_css_provider_load_from_data(dbp->bp, tstr, -1, NULL);
        
// Add provider to button
gtk_style_context_add_provider (context, GTK_STYLE_PROVIDER(dbp->bp), GTK_STYLE_PROVIDER_PRIORITY_USER);
        
// Give the button the CSS style/class corresponding to the one we just created for it
snprintf(value, SHORT_STR, "btnid_%02d", buttonId); // Sets default colour from table
gtk_style_context_add_class(context, value);

动态改变按钮的颜色:

// Create new CSS
snprintf(temp_css, LONG_STR, ".btnid_%02dbackground: #%06X", btnID, new_colour);
// Re-load into provider
gtk_css_provider_load_from_data(dbp->bp, tstr, -1, NULL);

就是这样,它可以工作,而且不会泄漏内存。

【讨论】:

以上是关于修改 GTK 按钮样式/CSS 并立即更新/刷新的主要内容,如果未能解决你的问题,请参考以下文章

同事打开两个JSP网页A和B,在其中一个A网页中修改数据,按"提交"之后,B网页要立即刷新,更新数据。

vue项目中直接用的audio标签,对样式进行修改并单独存放在一个css文件中 引用后页面每次刷新之后才会出现

GtkCssProvider 和 CSS 样式的问题

使用按钮助记符不会更新第二个微调按钮值

用SecureCRT软件修改字体样式和大小的技巧

gtkmm 3.10.1 中带有 CSS 的 Gtk::Box 样式问题