无法将 CSS 应用于 GtkEntry 小部件 (GTK3 / gi / Python) 不工作

Cannot apply CSS to GtkEntry Widget (GTK3 / gi / Python) Not Working

我一直无法弄清楚我做错了什么。我敢肯定这很简单,但逃避了我。即使在下面的示例中,我也无法正常工作。我似乎无法在单个 GtkWindow 中将 CSS 样式应用于 GtkEntry 小部件。我只是想把输入框的背景变成红色。

我审查过的所有内容和我见过的示例都如下所示,似乎没有其他人被难倒。

这是我的 Python:

import gi
gi.require_version('Gtk', '3.0')
gi.require_version('Gdk', '3.0')
from gi.repository import Gtk
from gi.repository import Gdk

builder = Gtk.Builder()
builder.add_from_file("entry.glade")

window = builder.get_object('window1')
window.connect('destroy', Gtk.main_quit)

css = "#red { background-image: linear-gradient(red); }"
provider = Gtk.CssProvider()
provider.load_from_data(css)
Gtk.StyleContext().add_provider_for_screen(Gdk.Screen.get_default(), provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)

entry = builder.get_object('entry1')
entry_style_context = entry.get_style_context()
entry_style_context.add_class("red")

window.show_all()

Gtk.main()

这里是林间空地 XML:

<?xml version="1.0" encoding="UTF-8"?>
<interface>
  <requires lib="gtk+" version="3.0"/>
  <!-- interface-naming-policy project-wide -->
  <object class="GtkWindow" id="window1">
    <property name="can_focus">False</property>
    <child>
      <object class="GtkVBox" id="vbox1">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <child>
          <object class="GtkEntry" id="entry1">
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <property name="invisible_char">●</property>
            <property name="primary_icon_activatable">False</property>
            <property name="secondary_icon_activatable">False</property>
            <property name="primary_icon_sensitive">True</property>
            <property name="secondary_icon_sensitive">True</property>
          </object>
          <packing>
            <property name="expand">True</property>
            <property name="fill">True</property>
            <property name="position">0</property>
          </packing>
        </child>
      </object>
    </child>
  </object>
</interface>

如果我将 CSS 设置为 .entry { background-image: linear-gradient(red); } 它可以工作,但是所有 GtkEntry 框都会是红色的(我不想要)。

我到底错过了什么?

好吧,好吧,换个思路再看一遍,我想我已经弄明白了。我不确定它为什么会这样工作,但希望有人比我更聪明。

出于某种原因,我需要以点表示法指定小部件类型和 class 名称,因为散列表示法在 CSS/HTML 领域无法正常工作。

工作:css = "#foo { background-image: linear-gradient(red); }

确实有效:css = "entry.foo { background-image: linear-gradient(red); }

我已经通过向 Glade 添加第二个输入框并执行以下操作验证了这一点:

css = """
.entry.red { background-image: linear-gradient(red); }
.entry.blue { background-image: linear-gradient(blue); }
"""
provider = Gtk.CssProvider()
provider.load_from_data(css)
Gtk.StyleContext().add_provider_for_screen(Gdk.Screen.get_default(), provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)

builder.get_object('entry1').get_style_context().add_class("red")
builder.get_object('entry2').get_style_context().add_class("blue")

现在我有一个红色和一个蓝色的输入框。

在常规浏览器 CSS 中,#foo 指代 ID 为 foo 的 HTML 元素(设置为 id="foo")和 .foo 指的是样式为 class 的元素(设置为 class="foo",或多个 class 元素,例如 class="foo bar"。)

在 GTK CSS 中,ID 转换为小部件名称(例如 entry.set_name('foo') 或 XML 文件中的 <property name="name">foo</property>;不幸的是 not 与 XML 文件中的 id="foo" 相同)并且 class 仍然是 class 样式(但在 GTK 中它设置为 entry.get_style_context().add_class('foo')。由于您的小部件具有样式 class 但没有名称,因此您必须使用点语法。

Question: Apply CSS to a GtkEntry Widget

正如 ptomato 在他的回答中所描述的那样,如果您没有为您的小部件定义 name,则不能使用 css = "#red ...

定义小部件 name,使用:

  • glade 文件中:<property name="name">red</property>
  • 在脚本中:entry = builder.get_object('entry1') entry.set_name('red')


Method 1: Using a widgets name, css = b"#entry ...:

  1. glade 文件中的小部件 name 设置为 entry
        <child>
          <object class="GtkEntry" id="entry1">
            <property name="name">entry</property>
    
  2. 使用小部件名称 entry:

    定义您的 CSS
        css = b"#entry {background-image: linear-gradient(red, orange); color: white;}"
    

    Working example, using a widgets name:

    class App:
        def __init__(self):
            super().__init__()
    
            builder = Gtk.Builder()
            builder.add_from_file("entry.glade")
    
            window = builder.get_object('window1')
            window.connect('destroy', Gtk.main_quit)
    
            css = b"#entry {background-image: linear-gradient(red, orange);}"
            provider = Gtk.CssProvider()
            provider.load_from_data(css)
            Gtk.StyleContext()\
                .add_provider_for_screen(Gdk.Screen.get_default(),
                                         provider,
                                         Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
    
            window.show_all()
    
    if __name__ == "__main__":
        main = App()
        Gtk.main()
    

Method 2: Using a widgets style class, css = b".entry.red ...:

  • Gtk.Widget.get_style_context, Gtk.StyleContext.add_class

    1. 使用嵌套样式定义 CSS class .entry, .red, .blue:
            css = b"""
            .entry {color: white;}
            .entry.red {background-image: linear-gradient(red, orange);}
            .entry.blue {background-image: linear-gradient(blue, lightblue);}
    
    1. 将命名样式 classes 添加到小部件:
            entry1 = builder.get_object('entry1')
            entry1.get_style_context().add_class("entry")
            entry1.get_style_context().add_class("red")
    
            # the same for `entry2`
            ...
    

    Working example using a widgets style class:

    class App:
        def __init__(self):
            super().__init__()
    
            builder = Gtk.Builder()
            builder.add_from_file("entry.glade")
    
            window = builder.get_object('window1')
            window.connect('destroy', Gtk.main_quit)
    
            css = b"""
            .entry { color: white;}
            .entry.red { background-image: linear-gradient(red, orange);}
            .entry.blue { background-image: linear-gradient(blue, lightblue);}
            """
            provider = Gtk.CssProvider()
            provider.load_from_data(css)
            Gtk.StyleContext()\
                .add_provider_for_screen(Gdk.Screen.get_default(),
                                         provider,
                                         Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
    
            entry1 = builder.get_object('entry1')
            entry1.set_text('TEST')
            entry1.get_style_context().add_class("entry")
            entry1.get_style_context().add_class("red")
    
            entry2 = builder.get_object('entry2')
            entry2.set_text('TEST')
            entry2.get_style_context().add_class("entry")
            entry2.get_style_context().add_class("blue")
    
            window.show_all()
    
    if __name__ == "__main__":
        main = App()
        Gtk.main()
    

使用 Python 测试:3.5 - gi.__version__:3.22.0 - Glade 3.20.0