如何为 GtkTreeView 单元格添加悬停效果
How to add a hover effect to a GtkTreeView cell
我有一个 GtkTreeView
,其中包含两列文本类型(例如 G_TYPE_STRING
),我正在使用 GtkCellRendererText
来呈现该列。
当鼠标进入和离开某个单元格然后悬停或突出显示该单元格时,为什么我可以做出反应。
例如,当鼠标进入单元格渲染器时,我想在文本中加下划线,以便提供视觉线索,表明可以单击单元格以执行操作。
如果存在 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 )
完成任务的方法有很多。下面是几个示例,由水平线分隔。
最简单,在某些方面也是最好的选择是在 GtkTreeView 中简单地将鼠标光标更改为手指(与您在浏览器中指向 link 时看到的鼠标光标相同) .
假设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"));
有了这个,鼠标指针将成为视图中所有行的手指,不包括 header 行。
您可以使用的一组游标名称(而不是上面的 "pointer"
)在 GDK3 文档中列出 here。
不利的是,如果树视图中有空行或分隔行,鼠标指针看起来仍然像手指。
您可以通过应用 application-specific 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);
创建主 window 之后。 (当然,您可以在 CSS 片段中包含所有 application-specific CSS 覆盖。)
但是,至少在 gtk+ 3.18.9 上,渲染器似乎不支持此处的 text-decoration
或 font
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 中悬停的行将变成下划线。
请注意,您悬停的行中的所有单元格都将突出显示,而不仅仅是您悬停的 cell/column。这是因为在 GtkTreeView 中,行(或索引)是被操作的单位(而不是特定列上的特定单元格)。
如果您仅对 GtkTreeView 中的某些列使用上述渲染器,即使鼠标悬停在该行的其他列上,这些列中的文本也会带有下划线。
另请注意,如果您不希望所有行都指示可点击性,您可以在数据模型中添加第三列 -- name "sensitive"
,为 gboolean 类型键入 G_TYPE_BOOLEAN
;值 TRUE
如果该行是可点击的,FALSE
如果该行是 non-clickable -- 并将 custom_cell_renderer_text_render()
中的 if
子句更改为
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 属性相关联。
我有一个 GtkTreeView
,其中包含两列文本类型(例如 G_TYPE_STRING
),我正在使用 GtkCellRendererText
来呈现该列。
当鼠标进入和离开某个单元格然后悬停或突出显示该单元格时,为什么我可以做出反应。
例如,当鼠标进入单元格渲染器时,我想在文本中加下划线,以便提供视觉线索,表明可以单击单元格以执行操作。
如果存在 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 )
完成任务的方法有很多。下面是几个示例,由水平线分隔。
最简单,在某些方面也是最好的选择是在 GtkTreeView 中简单地将鼠标光标更改为手指(与您在浏览器中指向 link 时看到的鼠标光标相同) .
假设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"));
有了这个,鼠标指针将成为视图中所有行的手指,不包括 header 行。
您可以使用的一组游标名称(而不是上面的 "pointer"
)在 GDK3 文档中列出 here。
不利的是,如果树视图中有空行或分隔行,鼠标指针看起来仍然像手指。
您可以通过应用 application-specific 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);
创建主 window 之后。 (当然,您可以在 CSS 片段中包含所有 application-specific CSS 覆盖。)
但是,至少在 gtk+ 3.18.9 上,渲染器似乎不支持此处的 text-decoration
或 font
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 中悬停的行将变成下划线。
请注意,您悬停的行中的所有单元格都将突出显示,而不仅仅是您悬停的 cell/column。这是因为在 GtkTreeView 中,行(或索引)是被操作的单位(而不是特定列上的特定单元格)。
如果您仅对 GtkTreeView 中的某些列使用上述渲染器,即使鼠标悬停在该行的其他列上,这些列中的文本也会带有下划线。
另请注意,如果您不希望所有行都指示可点击性,您可以在数据模型中添加第三列 -- name "sensitive"
,为 gboolean 类型键入 G_TYPE_BOOLEAN
;值 TRUE
如果该行是可点击的,FALSE
如果该行是 non-clickable -- 并将 custom_cell_renderer_text_render()
中的 if
子句更改为
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 属性相关联。