如何将悬停效果添加到GtkTreeView单元格

时间:2017-02-08 14:18:56

标签: c gtk3

我有一个GtkTreeView,其中包含两列文字类型(例如G_TYPE_STRING),我正在使用GtkCellRendererText来呈现该列。

当鼠标进入并离开某个细胞然后悬停或突出显示细胞时,有什么可以反应的原因。

例如,我希望在鼠标输入时为单元格渲染器中的文本加下划线,以便提供可以单击单元格以执行操作的直观线索。

2 个答案:

答案 0 :(得分:2)

如果PRELIT标志存在,您可以创建自定义CellRendererText并设置下划线属性。

我只知道Python:

class My_CellRendererText( Gtk.CellRendererText ):
def __init__( self ):
    super().__init__()

def do_render( self, cr, widget, background_area, cell_area, flags ):
    self.props.underline = ( ( flags & Gtk.CellRendererState.PRELIT ) != 0 )
    return Gtk.CellRendererText.do_render( self, cr, widget, background_area, cell_area, flags )

GObject.type_register( My_CellRendererText )

答案 1 :(得分:1)

有很多方法可以完成任务。下面是几个例子,用水平线分隔。

最简单的,在某些方面最好的选项是在GtkTreeView中简单地将鼠标光标更改为手指(与指向链接时在浏览器中看到的鼠标光标相同)。

让我们说GtkTreeView *view是我们感兴趣的观点。之后您拨打了gtk_widget_show_all(window);,您可以致电

GdkWindow  *win = gtk_tree_view_get_bin_window(GTK_TREE_VIEW(view));
GdkDisplay *disp = gdk_window_get_display(win);
gdk_window_set_cursor(win, gdk_cursor_new_from_name(disp, "pointer"));

这样,鼠标指针将成为视图中所有行的手指,不包括标题行。

您可以使用的光标名称集(而不是上面的"pointer")在GDK3文档中列出了here

缺点是如果树视图或分隔符行中有空行,鼠标指针仍然看起来像手指那样。

您可以通过应用特定于应用程序的CSS悬停颜色来覆盖悬停颜色,例如

GtkTreeView:hover {
    color: #ff0000;
}

与例如

GtkCssProvider *css_provider;
css_provider = gtk_css_provider_new();
if (gtk_css_provider_load_from_data(css_provider, 
            "GtkTreeView:hover {\n"
            "    color: #ff0000;\n"
            "}\n"
            "", -1, NULL))
    gtk_style_context_add_provider_for_screen(gdk_screen_get_default(),
                GTK_STYLE_PROVIDER(css_provider),
                GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
g_object_unref(css_provider);
创建主窗口后

。 (当然,您可以在CSS片段中包含所有特定于应用程序的CSS覆盖。)

但是,至少在gtk + 3.18.9上,渲染器似乎不支持text-decorationfont CSS属性。 (GtkCssProvider似乎根本不支持cursor属性,以防你想知道。)

此外,由于这基本上覆盖了用户主题,并且Gtk +用户可能使用了许多可能的主题,因此以这种方式更改颜色在所有主题中看起来不太好。

如果您的GtkTreeView *view;包含可点击的行,并且您不需要选择任何内容(也就是说,您没有单独的按钮或导致操作应用的内容对于GtkTreeView中的所有选定行,您只需将选择设置为跟随鼠标光标:

gtk_tree_view_set_hover_selection(view, TRUE);

这会导致您悬停的行被选中,因此也会突出显示。您可能还希望一次将选择限制为一行:

gtk_tree_selection_set_mode(gtk_tree_view_get_selection(view),
                            GTK_SELECTION_SINGLE);

作为Herbalist already mentioned,您可以创建一个自定义GtkCellRendererText派生词,它会更改PangoUnderline underline属性,具体取决于正在呈现的文本单元格是否也是预照明(悬停):

#include <gtk/gtk.h>

#define CUSTOM_TYPE_CELL_RENDERER_TEXT           (custom_cell_renderer_text_get_type())
#define CUSTOM_CELL_RENDERER_TEXT(obj)           (G_TYPE_CHECK_INSTANCE_CAST((obj), CUSTOM_TYPE_CELL_RENDERER_TEXT, CustomCellRendererText))
#define CUSTOM_CELL_RENDERER_TEXT_CLASS(cls)     (G_TYPE_CHECK_CLASS_CAST((cls),    CUSTOM_TYPE_CELL_RENDERER_TEXT, CustomCellRendererTextClass))
#define CUSTOM_IS_CELL_RENDERER_TEXT(obj)        (G_TYPE_CHECK_INSTANCE_TYPE((obj), CUSTOM_TYPE_CELL_RENDERER_TEXT))
#define CUSTOM_IS_CELL_RENDERER_TEXT_CLASS(cls)  (G_TYPE_CHECK_CLASS_TYPE((cls),    CUSTOM_TYPE_CELL_RENDERER_TEXT))
#define CUSTOM_CELL_RENDERER_TEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj),  CUSTOM_TYPE_CELL_RENDERER_TEXT, CustomCellRendererTextClass))

GType  custom_cell_renderer_text_get_type(void) G_GNUC_CONST;

typedef struct {
    GtkCellRendererText  renderer;
} CustomCellRendererText;

typedef struct {
    GtkCellRendererTextClass  parent_class;
} CustomCellRendererTextClass;

G_DEFINE_TYPE(CustomCellRendererText, custom_cell_renderer_text, GTK_TYPE_CELL_RENDERER_TEXT);

void custom_cell_renderer_text_render(GtkCellRenderer *cell,
                                      cairo_t *cr,
                                      GtkWidget *widget,
                                      const GdkRectangle *backarea,
                                      const GdkRectangle *cellarea,
                                      GtkCellRendererState state)
{
    if (state & GTK_CELL_RENDERER_PRELIT) {
        const PangoUnderline prelit = PANGO_UNDERLINE_SINGLE;
        PangoUnderline curr;
        g_object_get(cell, "underline", &curr, NULL);
        g_object_set(cell, "underline", prelit, NULL);
        ((GtkCellRendererClass *)custom_cell_renderer_text_parent_class)->render(cell, cr, widget, backarea, cellarea, state);
        g_object_set(cell, "underline", curr, NULL);
    } else
        ((GtkCellRendererClass *)custom_cell_renderer_text_parent_class)->render(cell, cr, widget, backarea, cellarea, state);
}

void custom_cell_renderer_text_class_init(CustomCellRendererTextClass *cls)
{
    ((GtkCellRendererClass *)cls)->render = custom_cell_renderer_text_render;
    return;
}

void custom_cell_renderer_text_init(CustomCellRendererText *renderer)
{
    return;
}

GtkCellRenderer *custom_cell_renderer_text_new(void)
{
    return g_object_new(CUSTOM_TYPE_CELL_RENDERER_TEXT, NULL);
}

如果您在GtkTreeView代码中将gtk_cell_render_text_new()替换为custom_cell_render_text_new()(并将GtkCellRenderText *更改为CustomCellRenderText *),则您在GtkTreeView中悬停的行将加下划线

请注意,您悬停在行中的所有单元格都会突出显示,而不仅仅是您悬停在其上的单元格/列。这是因为在GtkTreeView中,行(或索引)是被操作的单元(而不是特定列上的特定单元格)。

如果您仅将上述渲染器用于GtkTreeView中的某些列,则即使鼠标悬停在该行上的某些其他列上,这些列中的文本也会加下划线。

另请注意,如果您不希望所有行都表示可点击性,则可以在数据模型中添加第三列 - 名称"sensitive",键入G_TYPE_BOOLEAN以获取gboolean类型;如果该行可点击,则为TRUE;如果该行不可点击,则为FALSE - 并将if中的custom_cell_renderer_text_render()子句更改为

    const GtkStateFlags  flags = gtk_cell_renderer_get_state(cell, widget, state);
    if ((state & GTK_CELL_RENDERER_PRELIT) &&
       !(flags & GTK_STATE_FLAG_INSENSITIVE)) {

Gtk +会正常呈现带TRUE的行,带有FALSE的行作为分隔符或禁用文本,因为模型中的列名称会自动与同名的GtkCellRenderer属性相关联。