【问题标题】:GtkStyleProvider - providing own implementationGtkStyleProvider - 提供自己的实现
【发布时间】:2016-12-22 05:46:13
【问题描述】:

我正在尝试提供我自己的 GtkStyleProvider 实现,因为在我的情况下,“普通”CSS 提供程序需要大量工作和额外处理。

我希望能够提供基于某些内部状态的小部件样式,并且要在 CSS 中做到这一点,我必须写出一大串 CSS(将 Pango.FontDescriptions 之类的东西翻译成 CSS 样式的声明) 基于状态的任何变化,然后将其输入到GktCssProvider 中,该GktCssProvider 会将其返回到 Gtk-land。与自定义提供程序相比,它只会(以某种方式)发出信号,表明其客户端小部件应向其询问样式,并直接根据状态分发新样式。

GtkStyleProvider 似乎是实现这一目标的一种方式——我可以创建一个基于某种状态返回样式的提供程序,并将其作为样式提供程序添加到相关的GtkStyleContext。 (C)接口是

// deprecated - return NULL in new code
GtkIconFactory *      gtk_style_provider_get_icon_factory (
                                   GtkStyleProvider *provider,
                                   GtkWidgetPath *path);)  
// deprecated - return NULL in new code
GtkStyleProperties *  gtk_style_provider_get_style (
                                   GtkStyleProvider *provider,
                                   GtkWidgetPath *path))
// return true if property found and has a value, else false
gboolean              gtk_style_provider_get_style_property (
                                   GtkStyleProvider *provider,
                                   GtkWidgetPath *path,
                                   GtkStateFlags state,
                                   GParamSpec *pspec,
                                   GValue *value);

为此,我写了这样的东西,我希望它可以工作,但什么也不做,因为它应该总是报告属性未设置:

# compile with: valac styleprov.vala --pkg gtk+-3.0 --pkg gdk-3.0
using Gtk;
using Gdk;

public class DerivedStyleProvider : Object, Gtk.StyleProvider
{
    public unowned Gtk.IconFactory get_icon_factory (Gtk.WidgetPath path)
    {
        return (Gtk.IconFactory) null; // Evil cast to work around buggy declaration in VAPI file
    }

    public Gtk.StyleProperties get_style (Gtk.WidgetPath path)
    {
        return (Gtk.StyleProperties) null; // Evil cast to work around buggy declaration in VAPI file
    }

    public bool get_style_property (Gtk.WidgetPath path,
                Gtk.StateFlags state,
                GLib.ParamSpec pspec,
                out GLib.Value value)
    {
        stdout.printf("get_style_property");
        // Compiler happiness for testing
        value = Value (typeof (string));
        return false; //TODO
    }
}

public class styleprov.MainWindow : Gtk.Window
{
    construct {
        DerivedStyleProvider styleProvider = new DerivedStyleProvider();

        // but this would work
        //Gtk.CssProvider styleProvider = new Gtk.CssProvider();
        //styleProvider.load_from_data("*{ background-color: #ff0000; }");

        StyleContext.add_provider_for_screen(this.get_screen(),
                                             styleProvider,
                                             Gtk.STYLE_PROVIDER_PRIORITY_USER);
    }
}

class styleprov.Main : GLib.Object
{
        public void run() {
            styleprov.MainWindow mainWindow = new styleprov.MainWindow();
            mainWindow.show_all();
        }

        public static int main (string[] args) {
            Gtk.init (ref args);

            Main app = new Main();
            app.run();
            Gtk.main ();
            return 0;
        }
}

这编译OK,运行起来,但几乎喷出警告:

(styleprov:32365): GLib-GObject-WARNING **: gsignal.c:2523: signal '-gtk-private-changed' is invalid for instance '0x1154ac0' of type 'DerivedStyleProvider'
(styleprov:32365): Gtk-WARNING **: (gtkstylecascade.c:256):gtk_style_cascade_lookup: code should not be reached
(styleprov:32365): Gtk-WARNING **: (gtkstylecascade.c:256):gtk_style_cascade_lookup: code should not be reached
...several of these....

尽管有警告,get_style_property() 方法似乎从未被调用,因此无法提供自定义样式。

DerivedStyleProvider 替换为“普通”CSS 提供程序可以正常工作。

实现自定义GtkStyleProvider(任何语言)的正确方法是什么?

【问题讨论】:

  • 我快速浏览了 GtkCssProvider,它实现了 两个 接口,GtkStyleProviderGtkStyleProviderPrivate。您可能还必须为第二个接口提供实现。虽然我不是 Gtk+ 专家...
  • 顺便说一句:为什么你必须大量自定义你的 ui 样式呢?我在这里闻到了XY problem。您可能想退后一步,重新考虑您的设计。使用 Clutter、Cairo 或类似的东西自己绘制 UI 可能是另一种选择。
  • 它实际上并没有大量的样式或非常复杂,它只是将 CSS 构造为字符串,对我来说似乎是迂回的,我被GtkStyleProvider 的 API 承诺分心,结果是不能按我想象的方式使用。

标签: css c gtk styling vala


【解决方案1】:

查看GtkCssProvider 的实现,它似乎不仅使用了GtkStyleProviderInterface,还使用了GtkStyleProviderPrivateInterface,以及许多复杂的自定义绕过(显然是出于效率原因,根据他 GTK+ IRC 频道上的友好人士),我决定只使用普通的 CSS 方法,只处理手动构建 CSS 作为字符串。

机制是:

  • GtkCssProvider 已创建
  • Provider 使用gtk_style_context_add_provider()(或全局gtk_style_context_add_provider_for_screen())附加到相关样式上下文
  • 数据管理器发送数据已更改的信号
  • 这被我的 Data->CSS 翻译器捕获,它为相关的GtkCssProvider 生成一个新的 CSS 字符串
  • 此字符串通过gtk_css_provider_load_from_data() 输入到现有提供程序。
  • 由该更新引起的任何 UI 更改都将自动发生

我想这个问题很可能是我不完全理解 GTK+ 在下面是如何工作的。如果您将 CSS 视为 UI 的 规范样式“oracle”,那么我认为更新 CSS 确实实际上是正确的方法,我期待低级访问在技术上可能是可行的,但在 GTK+ 方式中并不“正确”。

这种低级访问是我对其他框架的期望,在这些框架中,您(仅)可以直接控制小部件的“背景颜色”之类的样式,并且没有 CSS 层来抽象它,但是只是它在 GTK+ 中的工作方式(不再)。

至少,我是这么理解的!

【讨论】:

  • 是的,这也是我得到的。像你一样,我确实希望我可以直接访问这些属性,但我知道事情是这样编写的,CSS 是源代码。将其转换为 GObject 内容的内部转换不是公共 API,可能是因为对此做出承诺将是维护的噩梦,并且会阻碍解析器重写/优化/等。由于样式机制需要能够使用 CSS,因此将其作为唯一的路由是有意义的,那么它们只需要维护一个 API 界面。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-11-10
  • 1970-01-01
  • 2010-10-12
  • 1970-01-01
  • 1970-01-01
  • 2017-02-22
  • 2016-05-02
相关资源
最近更新 更多