设置Gtk3 MenuItem的鼠标悬停背景颜色

5
我有一个带弹出菜单的托盘图标。我试图设置此弹出菜单中菜单项的背景颜色。我能够设置文本颜色,但无法设置菜单项的背景颜色。
出现的背景是默认的Ubuntu橙色,我无法覆盖它。
我创建了一个演示此问题的样例应用程序。只需将其复制粘贴到.py文件中,它就可以运行。
from gi.repository import Gtk, Gdk
import sys

class TrayIcon:

    def __init__(self):
        self.statusicon = Gtk.StatusIcon()
        self.statusicon.set_from_stock(Gtk.STOCK_MEDIA_PLAY)
        self.statusicon.connect("popup-menu", self.OnShowPopupMenu)
        window = Gtk.Window()

    def OnShowPopupMenu(self, icon, button, time):
       menu = Gtk.Menu()
       first = self.GetMenuItem("First")
       second = self.GetMenuItem("Second")
       menu.append(first)
       menu.append(second)
       menu.show_all()
       menu.popup(None, None, lambda w,x: self.statusicon.position_menu(menu, self.statusicon), self.statusicon, 3, time)

    def GetMenuItem(self, txt):
    menuItem = Gtk.MenuItem(txt)

    screen = Gdk.Screen.get_default()
    css_provider = Gtk.CssProvider()
    #css_provider.load_from_data("GtkWidget { color:white; background-color: green; } GtkWidget:hover,GtkWidget:selected { color:white; background-color:pink;}")
    css_provider.load_from_data("GtkMenuItem { color:#0f0; background-color: #f00; } GtkMenuItem:hover,GtkMenuItem:selected { color:#00f; background-color:#f00; font-weight:bold;}")
    context = Gtk.StyleContext()
    context.add_provider_for_screen(screen, css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)

    menuItem.connect("button_press_event", self.exit)

    return menuItem

    def exit(self, a,b):
    sys.exit()

TrayIcon()
Gtk.main()

对于GtkMenuItem,正常背景和:hover背景被忽略了。对于GtkWidget,:hover背景也被忽略了。我的目标是在不禁用菜单项的情况下防止Ubuntu橙色显示出来。
有没有一种方法可以设置GtkMenuItem的背景和悬停/鼠标经过颜色?(不使用'import gtk')
我正在使用Ubuntu 12.04,默认主题。
编辑1:为了更清楚地说明,这就是我想做的事情,但不使用'import gtk'。
    #Prevent background color when mouse hovers
    style = menuItem.get_style().copy()
    style.bg[gtk.STATE_SELECTED] = style.bg[gtk.STATE_NORMAL]
    menuItem.set_style(style)

编辑2:我也尝试过override_background_color()和modify_bg,但在悬停时仍然会显示橙色。以下是我尝试过的变体。

    menuItem.override_background_color(Gtk.StateFlags.NORMAL,Gdk.RGBA(1.0,0.0,0.0,1))
    menuItem.modify_bg(Gtk.StateFlags.NORMAL,Gdk.color_parse("red"))
    menuItem.override_background_color(Gtk.StateFlags.NORMAL, Gdk.RGBA(1.0, 1.0, 1.0, 1.0))
    menuItem.override_background_color(Gtk.StateFlags.SELECTED, Gdk.RGBA(1.0, 1.0, 1.0, 1.0))
    menuItem.override_background_color(Gtk.StateFlags.FOCUSED, Gdk.RGBA(1.0, 1.0, 1.0, 1.0))

编辑3: 已提供答案,请参见此帖子


1
最好不要没有真正的好理由就更改颜色和背景颜色。一些用户因为视觉障碍,比如色盲,而有特定的桌面主题和颜色,你会让这些人无法使用你的应用程序。 - ptomato
是的,但在这种情况下有一个特定的原因和要求来更改背景颜色,因此才会提出这个问题。我故意不包括原因,因为这都是内部办公室的事情。 - Mendhak
2个回答

4

经过大量的挖掘,答案最终变得有些晦涩。

  • background-color 不起作用。我必须使用 background
  • 我还必须使用 -unico-inner-stroke-width

最终我在 Ubuntu 主题的 GTK3 CSS 文件中找到了问题所在,文件位置如下:

/usr/share/themes/Ambiance/gtk-3.0/gtk-widgets.css

我从上述CSS文件中得到了-unico-inner-stroke-width属性。 我无法确定为什么我的脚本中的background-color被忽略了,但至少在Ubuntu 12.04上是这样的。

我还被迫“重新设置”我正在更改的元素的背景和边框颜色,否则它们会出现奇怪的外观。 这是我不得不使用的最小CSS。

                    GtkMenuItem 
                    {
                        border:@bg_color;
                        background:@bg_color;
                    }

                    GtkMenuItem:hover
                    {
                        background:@selected_bg_color;
                    }

                    GtkWidget
                    {
                        border: @bg_color;
                    }

                    #mymenu:hover
                    {
                        color:@fg_color;
                        background: @bg_color;
                        -unico-inner-stroke-width: 0;
                    }

在这个例子中,我将单个GtkMenuItem的悬停颜色设置为与背景颜色相同,但如果您想将颜色设置为其他颜色,则需要根据您的需求更改background属性。
结果是一个没有悬停颜色的工作菜单项。
以下是完整的Python代码:
from gi.repository import Gtk, Gdk
import sys


class TrayIcon:

    def __init__(self):
        self.statusicon = Gtk.StatusIcon()
        self.statusicon.set_from_stock(Gtk.STOCK_MEDIA_PLAY)
        self.statusicon.connect("popup-menu", self.OnShowPopupMenu)
        self.statusicon.set_tooltip_text("HELLO")
        window = Gtk.Window()

    def OnShowPopupMenu(self, icon, button, time):

        display = Gdk.Display.get_default()
        screen = display.get_default_screen()

        css_provider = Gtk.CssProvider()

        gtk3Css = """GtkMenuItem {
                        border:@bg_color;
                        background:@bg_color;
                    }

                    GtkMenuItem:hover
                    {
                        background:@selected_bg_color;
                    }

                    GtkWidget
                    {
                        border: @bg_color;
                    }

                    #mymenu:hover
                    {
                        color:@fg_color;
                        background: @bg_color;
                        -unico-inner-stroke-width: 0;
                    }"""
        css_provider.load_from_data(gtk3Css)
        context = Gtk.StyleContext()
        context.add_provider_for_screen(screen, css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)

        menu = Gtk.Menu()
        #menu.set_name('mymenu')
        first = self.GetMenuItem("First")
        first.set_name('mymenu')
        second = self.GetMenuItem("Second")
        menu.append(first)
        menu.append(second)
        menu.show_all()
        menu.popup(None, None, lambda w,x: self.statusicon.position_menu(menu, self.statusicon), self.statusicon, 3, time)

    def GetMenuItem(self, txt):
    menuItem = Gtk.MenuItem()
    menuItem.set_label(txt)

    menuItem.connect("button_press_event", self.exit)

    return menuItem

    def exit(self, a,b):
    sys.exit()


TrayIcon()
Gtk.main()

如果你想设置另一个背景颜色,可以在上述CSS中进行更改。
                    GtkMenuItem:hover
                    {
                        background:purple;
                        -unico-inner-stroke-width: 0;
                    }

(或在#mymenu:hover中执行)

输入图像描述

总之,我认为这可能是一个仅限于Ubuntu 12.04或GTK 3.4.2的问题,我通过运行以下命令得出结论:

pkg-config --modversion gtk+-3.0

但是我没有专业知识来确定这个问题的起源。


抱歉发表这篇“死帖”... 背景颜色“无法工作”的原因通常是主题使用背景图设置了渐变。因此,背景颜色在技术上是有效的,只是被背景“图像”隐藏了起来。使用“background-image: none;”可以解决这个问题。 - Justin Sane
只使用“background”也可以,因为它是许多属性的速记,包括-color和-image。 - Justin Sane

1

嗯,这是关于C而不是Python,但对我来说可以工作。我将菜单命名为“mymenu”,以便您可以在不使用GtkLabel的情况下对其进行样式设计,因为那会影响应用程序中的任何其他标签。

/* COMPILE WITH: gcc -Wall -o icon3 `pkg-config --cflags --libs gtk+-3.0` icon3.c */

#include <gtk/gtk.h>
#include <string.h>  /* for CSS */

static void cb_left_click(GtkStatusIcon *icon, gpointer data)
{
 static GtkWidget *window = NULL;

if (window == NULL) {
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(window), "Status Icon");

    g_signal_connect( window, "delete-event", G_CALLBACK(gtk_main_quit), NULL );
    gtk_widget_show(window);
}
}

static void cb_right_click(GtkStatusIcon *icon, int button, int time, gpointer data)
{
    GtkWidget *menu;

menu = gtk_menu_new ();
gtk_widget_set_name(GTK_WIDGET(menu),"mymenu");
GtkWidget *item1 = gtk_menu_item_new_with_label("First");

GtkWidget *item2 = gtk_menu_item_new_with_label("Second");

gtk_menu_shell_append(GTK_MENU_SHELL(menu), item1);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), item2);

    gtk_widget_show_all(menu);
    gtk_menu_popup(GTK_MENU(menu),
                        NULL,
                        NULL,
                        gtk_status_icon_position_menu,
                        icon,
                        button,
                        time);
}

int main(int argc, char *argv[])
{
GtkStatusIcon *icon;
/*-- CSS ------------------*/
  GtkCssProvider *provider;
  GdkDisplay *display;
  GdkScreen *screen;
/*---------------------------*/

gtk_init(&argc, &argv);

icon = gtk_status_icon_new_from_stock (GTK_STOCK_MEDIA_PLAY);

g_signal_connect (G_OBJECT(icon), "activate", G_CALLBACK(cb_left_click), NULL);
g_signal_connect (G_OBJECT(icon), "popup-menu", G_CALLBACK(cb_right_click), NULL);

/*---------------- CSS ----------------------------------------------------------------------------------------------------*/
  provider = gtk_css_provider_new ();
  display = gdk_display_get_default ();
  screen = gdk_display_get_default_screen (display);
  gtk_style_context_add_provider_for_screen (screen, GTK_STYLE_PROVIDER (provider),     GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);

  gsize bytes_written, bytes_read;

 const gchar* home = "/home/mike/icon3.css";     

  GError *error = 0;

  gtk_css_provider_load_from_path (provider,
                               g_filename_to_utf8(home, strlen(home),
                               &bytes_read, &bytes_written, &error),
                               NULL);
  g_object_unref (provider);
/*-------------------------------------------------------------------------------------------------------------------------*/

    gtk_main();
    return 0;
}

CSS文件:

#mymenu {       
    background-color: white;
    color: green;
    font-weight:bold;
}

#mymenu :hover {
    background-color: red;
    color: blue;
    font-weight:bold;
}

由于我不熟悉C语言,所以我很难让它正常工作。根据我的翻译能力,我正在做的与你所做的相同,区别在于你使用了#mymenu而不是type。无论如何,背景都没有被设置。你也在使用Ubuntu吗?你能否发布一张截图展示它的运行情况?当我尝试按代码中注释部分所示进行编译时,我会得到几个未定义错误。我更喜欢Python,因为我不确定C代码中是否有一些步骤在我的代码中被省略了。 - Mendhak
我使用的是 Ubuntu Natty,gtk+-3.2.3。很抱歉我不会 Python。在你的函数 css_provider.load_from_data() 中,正常状态和悬停状态、选定状态的背景颜色都相同:#f00。http://img809.imageshack.us/img809/1474/iconcd.png - mike
我终于找到了答案,可能与我们的Ubuntu或GTK3版本有关。我已经单独发布了我的答案。感谢你的努力,至少看了这个问题。 - Mendhak

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接