【问题标题】:Best way to set Entry Background Color in Python GTK3 and set back to default在 Python GTK3 中设置条目背景颜色并设置回默认值的最佳方法
【发布时间】:2016-08-22 00:30:38
【问题描述】:

为一个条目设置背景颜色并将其设置回默认颜色的最佳方法是什么?

我的脚本现在可以运行,但我很确定这不是最好的方法。
另外我还有两个问题:

  1. 如果我插入一个不包含字符串“red”或“green”的文本并选择此文本,我看不到我的选择,因为它全是白色的。
  2. 我认为有比我在 CSS 文本中插入 self.entry_default_background_color_str 的方式更好的方法。

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

class Window(Gtk.Window):

    def __init__(self):

        self.screen = Gdk.Screen.get_default()
        self.gtk_provider = Gtk.CssProvider()
        self.gtk_context = Gtk.StyleContext()
        self.gtk_context.add_provider_for_screen(self.screen, self.gtk_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)


        Gtk.Window.__init__(self, title="Check Input")
        self.set_size_request(300, 80)
        self.mainbox = Gtk.VBox()
        self.add(self.mainbox)

        # entry
        self.name_entry      = Gtk.Entry()
        self.name_entry.set_name("name_entry")
        self.mainbox.pack_start(self.name_entry, True, True, 0)
        self.name_entry.connect("changed", self.check_input)

        entry_context = self.name_entry.get_style_context()
        self.entry_default_background_color = entry_context.get_background_color(Gtk.StateType.NORMAL)
        self.entry_default_background_color_str = self.entry_default_background_color.to_string()

        self.show_all()


    def check_input(self, _widget=None):        
            if "red" in self.name_entry.get_text():
                self.gtk_provider.load_from_data('#name_entry { background: red; }')
            elif "green" in self.name_entry.get_text():
                self.gtk_provider.load_from_data('#name_entry { background: green; }')
            else:
                self.gtk_provider.load_from_data('#name_entry { background: ' + self.entry_default_background_color_str + '; }')


def main():
    window = Window()
    Gtk.main()


if __name__ == "__main__":
    main()

【问题讨论】:

  • 关于问题中代码的小注释,它使用self.name_entry而不是侦听器传递的小部件。虽然这可能只适用于一个Entry,但它不适用于多个,因此请使用听众传递的那个,否则可能会将您的样式应用于错误的Entry

标签: python css gtk3


【解决方案1】:

我将首先解决您提到的问题,因为它们可以深入了解 GTK 和 OP 代码中发生的情况。 主要问题的答案(以及执行此操作的正确代码)一直在答案的底部。


  1. 如果我插入一个不包含字符串“red”或“green”的文本并选择此文本,我看不到我的选择,因为它全是白色的。

发生这种情况的原因是因为使用了background 属性,这会将Entry 的所有背景相关属性设置为该颜色。所以无论是选择还是“真实”背景。

那么问题是我们使用什么属性,这是 GTK 的一部分,文档记录很差,但我们可以使用 GtkInspector 找到它,它可以让我们看到哪些样式属性正在发生变化。这产生了我们应该使用background-image 代替,background-color 用于选择的背景。

仅将background-image 设置为颜色不起作用,这会导致错误,因为需要图像。所以现在我们必须想办法让我们的color 变成我们可以设置为background-image 的东西,幸运的是,检查员向我们展示了 GTK 在内部的方式,即通过像这样包装颜色:linear-gradient(red)。这样做会创建一个可用作背景的统一红色图像。

将这些知识应用到您的代码中可以得到:

if "red" in self.name_entry.get_text():
    self.gtk_provider.load_from_data('#name_entry { background-image: linear-gradient(red); }')
elif "green" in self.name_entry.get_text():
    self.gtk_provider.load_from_data('#name_entry { background-image: linear-gradient(green); }')

  1. 我认为有比我在 CSS 文本中插入 self.entry_default_background_color_str 的方式更好的方法。

确实有更好的方法,那就是不要这样做。我们可以很容易地返回默认值,只需向CssProvider 提供一个空版本的 css,这将覆盖旧版本,从而删除任何旧样式属性,例如颜色。

将此与上一节结合起来,我们得出:

if "red" in self.name_entry.get_text():
    self.gtk_provider.load_from_data('#name_entry { background-image: linear-gradient(red); }')
elif "green" in self.name_entry.get_text():
    self.gtk_provider.load_from_data('#name_entry { background-image: linear-gradient(green); }')
else:
    self.gtk_provider.load_from_data('#name_entry {}')

为一个条目设置背景颜色并将其设置回默认颜色的最佳方法是什么?

现在我已经解决了您的代码的问题,现在这个问题很重要。您现在这样做的方式是替换 CSS 文件,它工作正常,但从长远来看确实效率低下。通常你会加载 CSS 并使用类和 id 来告诉它应用哪种样式。

下面我调整了你的代码来做到这一点,检查 cmets 以获得解释。

def __init__(self):

    screen = Gdk.Screen.get_default()
    gtk_provider = Gtk.CssProvider()
    gtk_context = Gtk.StyleContext()
    gtk_context.add_provider_for_screen(screen, gtk_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)

    # Create the window
    Gtk.Window.__init__(self, title="Check Input")
    self.set_size_request(300, 80)
    self.mainbox = Gtk.VBox()
    self.add(self.mainbox)

    # Load the CSS
    gtk_provider.load_from_data("""
    #name_entry.red { background-image: linear-gradient(red); }
    #name_entry.green { background-image: linear-gradient(green); }
    """)

    # Create the entry and give it a name which will be the ID
    name_entry = Gtk.Entry()
    name_entry.set_name("name_entry")
    self.mainbox.pack_start(name_entry, True, True, 0)

    # Add the listener
    name_entry.connect("changed", self.check_input)

    self.show_all()


def check_input(self, entry):
    # Get the style context for this widget
    entry_style_context = entry.get_style_context()

    # Check if our text contains red
    if "red" in entry.get_text():
        # Add the red class, so now the styling with .red is applied
        entry_style_context.add_class("red")

    # Check if our text contains green
    elif "green" in entry.get_text():
        # Add the red class, so now the styling with .green is applied
        entry_style_context.add_class("green")
    else:
        # When the text doesn't contain it remove the color classes to show the default behaviour
        entry_style_context.remove_class("red")
        entry_style_context.remove_class("green")

【讨论】:

  • 非常感谢!我对这个答案很满意:-)
  • 最新的GTK3推荐使用background-image: image(red);。不推荐使用带有 linear-gradient() 的一种颜色停止。
  • 好点,有机会测试一下会更新代码
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-05-24
  • 2014-11-03
  • 2022-10-18
  • 2013-10-26
  • 2022-07-05
  • 1970-01-01
  • 2017-05-13
相关资源
最近更新 更多