使用Python更改GtkTreeview中选定项的颜色

9

我有一个对话框,其中包含一个pygtk.treeview用于按优先级列出任务。每一行的背景颜色都是根据其优先级设置的,因此例如最高优先级具有浅红色背景。

行选择颜色不太容易更改。我可以使用treeview.modify_base(gtk.STATE_SELECTED, "#C4C4C4")进行设置,但没有颜色与用于增强优先级概念的颜色配合得很好。

我想到了将选择颜色更改为略微较深版本的用作普通行背景的颜色,因此在上面的示例中,这将是较深的红色。我尝试在treeselection的changed信号响应中调用上述函数,它确实有效,但会严重闪烁。

另一个想法是将选择更改为透明并在其周围放置边框,但据我所知,这是不可能的。

  1. 如何以上述方式更改选择颜色而不会闪烁?
  2. 我能否通过仅在行周围放置边框来显示选择内容?

注意:我知道这违反了用户选择的主题。我认为我有充分的理由。通过颜色指示优先级使其立即可识别。选择颜色隐藏了这一点。如果您有其他建议,我愿意听取,但需要保留用户可以识别优先级的简易性。


只有在有充分理由的情况下,才尝试覆盖用户的主题。 - ptomato
5个回答

4
您可以使用这里描述的方法进行操作-我已经进行了简要测试,并且可以在不闪烁的情况下完成工作。基本上,窍门是使用单元格渲染器的“Markup”属性。然而,有一个注意点:如果您想使用此方法更改背景颜色,则只会更改“实际”文本后面的背景,而不是整个行的背景。但是,如果您想更改文本颜色(使用<span foreground= ... ),这正是我想要的效果。

我有以下CellDataFunc(这是C#,但我希望它仍然有用):

private void CellDataFunc(Gtk.TreeViewColumn column, Gtk.CellRenderer cell, Gtk.TreeModel model, Gtk.TreeIter iter) {
    Item item = (Item) model.GetValue (iter, 0);
    if(cell is CellRendererText) {
        int id = (int)column.GetData("colId");
        string text = "";
        switch(id) {
            case 0: text = item.Name;  break;
            case 1: text = item.Size; break;
            case 2: text = item.Time.ToString();  break;                
        }
        //(cell as Gtk.CellRendererText).Text = text;
        if(item.Highlight) {
            (cell as Gtk.CellRendererText).Markup = 
                            "<span background=\"red\">"+text+"</span>";
        } else {
            (cell as Gtk.CellRendererText).Markup = text;
        }
    }
}

2
您可以在最左边添加一个单独的 pixbuf 单元格(比如与小图标相同大小),以指示选择。选定行可以使用更“实心”(饱和度更高)的颜色填充它。例如,如果您使用粉色背景表示高优先级,则可以使用红色作为选择指示器。或者您可以使用一个图标。
要使用颜色填充方法实现此操作,请执行以下操作:
  1. 按照 Tobias 的建议禁用内置高亮显示(“将 STATE_SELECTED 颜色设置为 STATE_NORMAL 颜色相同”)。
  2. 创建一个基于 gtk.gdk.Pixbuf 的窗口部件,该窗口部件允许您创建一个固定的颜色区域,可能使用 fill 方法。
  3. 为您的“选择”单元格使用 CellRendererPixbuf
您可以在选择更改时对“选择单元格”进行着色或取消着色,以指示哪一行被选中,或显示一个图标(例如股票符号)。
请注意,我还没有实现这个想法。它与通常的GTK选择指示有很大不同,因此(显然),请根据您的判断力决定是否可用。

他也可以使用pixbuf来指示优先级,并且完全不需要调整行颜色。 大多数 Mac 应用程序都结合了两者:选择会覆盖背景,除了一列中的一个小点。 - Tobias
我完全没想到那个:P 我记得我曾经用过的一个邮件阅读器在一列中有小的“向上”、“向下”、“双倍向上”和“双倍向下”的箭头符号来表示优先级。 - detly
我也考虑使用pixbuf来显示颜色。这可能是最好的选择,因为我预计选择不会覆盖图像。 - Jon

0

不确定你所说的闪烁是什么意思。要添加边框需要子类化TreeView。

我会将STATE_SELECTED颜色设置为与STATE_NORMAL完全相同,以禁用内置高亮功能。然后在每个列上设置一个data_func,并根据单元格渲染器是否被选中来更改一些颜色。

你可能已经为优先级做了这件事,所以只需将颜色乘以某个值以突出显示一行。


1
当我将STATE_SELECTED设置为STATE_NORMAL颜色时,它并没有禁用它,而是将颜色设置为相同的颜色,即白色。 - Jon
抱歉,我没有尝试过。我认为在那个点上透明颜色不存在。 - Tobias

0

对我来说,同时调用ModifyBase和ModifyText都起作用。只调用ModifyBase会将文本颜色更改为白色

在GTK C#中的示例:

treeViewList.ModifyBase(StateType.Selected, treeViewList.Style.Base(StateType.Normal)); treeViewList.ModifyText(StateType.Selected, treeViewList.Style.Text(StateType.Normal));


0
问题已经过时,但对其他人有用可能... 要完全禁用树中的选择并产生悬停效果: 1. 禁用树中的系统选择:
  _treeView.Selection.Mode = SelectionMode.None;
  • 处理MotionNotifyEvent事件:

    [ConnectBefore]
    private void TreeViewOnMotionNotifyEvent(object o, MotionNotifyEventArgs args)
    {
        TreePath treePath;
        TreeIter iter;
    
        int x = Convert.ToInt32(args.Event.X);
        int y = Convert.ToInt32(args.Event.Y);
    
        _treeView.GetPathAtPos(x, y, out treePath);
        _treeView.Model.GetIter(out iter, treePath);
    
        BindObject fieldModel = CellUtil.GetModelValue(_treeView.Model, iter, 1) as BindObject;
    
        HoverLine = _vievModel.BindObjectCollection.IndexOf(fieldModel);
    }
    
  • 在SetCellDataFunc方法中:

    BindObject fieldModel = CellUtil.GetModelValue(treeModel, iter, 1) as BindObject;
    int rowCount = _vievModel.BindObjectCollection.IndexOf(fieldModel);
    
    if (HoverLine == rowCount)
    {
            cellRenderer.CellBackgroundGdk = ThemeUtility.GdkOddSelectionColor; //您的选择颜色
    }
    else
    {
            cellRenderer.CellBackgroundGdk = ThemeUtility.SystemSelectionColor; //您的系统选择颜色
    }
    ...
    

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