如何手动绘制GtkTreeView扩展器

如何手动绘制GtkTreeView扩展器,gtk,gtktreeview,Gtk,Gtktreeview,我使用的是GtkTreeView小部件,我想更改打开和关闭子行的“扩展器”图标的外观:我希望图标是我们都熟悉的三角形,但它们显示为方框中的“+”和“-”符号 起初我认为必须有一个可以设置的样式枚举,但我找不到。然后,我想也许我可以在我的主题的gtkrc文件中设置一个样式属性,但我认为没有。最后,我尝试手动覆盖draw方法,如下所示: GtkWidget *pTreeView = gtk_tree_view_new_with_model((GtkTreeModel *)pTreeModel); (

我使用的是
GtkTreeView
小部件,我想更改打开和关闭子行的“扩展器”图标的外观:我希望图标是我们都熟悉的三角形,但它们显示为方框中的“+”和“-”符号

起初我认为必须有一个可以设置的样式枚举,但我找不到。然后,我想也许我可以在我的主题的gtkrc文件中设置一个样式属性,但我认为没有。最后,我尝试手动覆盖draw方法,如下所示:

GtkWidget *pTreeView = gtk_tree_view_new_with_model((GtkTreeModel *)pTreeModel);
(GTK_STYLE_GET_CLASS(pTreeView->style))->draw_expander = my_draw_expander_override;
但是,
my_draw\u expander\u override()
从未被调用,而且扩展器仍然是方框中的“+”和“-”图标

有人知道如何更改
GtkTreeView
扩展器图标的外观,或者自己绘制它们吗


提前多谢

这里是如何覆盖draw_expander的示例代码。你一定要看一下手册才能弄清楚所有的参数

#include <gtk/gtk.h>
#include <cairo.h>


enum {
  COL_1,
  N_COLS
};

void draw_expander (GtkStyle        *style,
                    GdkWindow       *window,
                    GtkStateType         state_type,
                    GdkRectangle    *area,
                    GtkWidget       *widget,
                    const gchar     *detail,
                    gint         x,
                    gint         y,
                    GtkExpanderStyle     expander_style) {


  cairo_t *cr;

  cr = gdk_cairo_create (window);

  cairo_set_source_rgb(cr, 0, 0, 0);

  cairo_move_to (cr, 0, 0);
  cairo_line_to (cr, 0, 10);
  cairo_line_to (cr, 10, 5);
  cairo_close_path (cr);

  cairo_stroke  (cr);
}


GtkWidget *build_view (); /* just supply your own */


int main (int argc, char *argv[]) {
  gtk_init (&argc, &argv);

  GtkWidget *window;
  GtkWidget *view;

  window = g_object_new (GTK_TYPE_WINDOW, NULL);  
  view = build_view ();
  gtk_container_add (GTK_CONTAINER (window), view);

  GtkStyle *style = gtk_widget_get_style (view);
  GtkStyleClass *klass = GTK_STYLE_GET_CLASS (style);

  klass->draw_expander = draw_expander;

  gtk_widget_show_all (window);
  gtk_main ();

  return 0;
}
#包括
#包括
枚举{
上校1,
努科尔斯
};
空心拉伸扩展器(GtkStyle*样式,
GdkWindow*窗口,
GtkStateType状态_类型,
GdkRectangle*区域,
GtkWidget*小部件,
const gchar*详细信息,
金特x,
金蒂,
GtkExpanderStyle扩展器(U型){
开罗*cr;
cr=gdk_cairo_create(窗口);
cairo\u set\u source\u rgb(cr,0,0,0);
开罗移动到(cr,0,0);
开罗线(cr,0,10);
开罗线(cr,10,5);
开罗路(cr);
脑卒中(cr);
}
GtkWidget*构建视图();/*你自己供应就行了*/
int main(int argc,char*argv[]){
gtk_init(&argc,&argv);
GtkWidget*窗口;
GtkWidget*视图;
window=g_object_new(GTK_TYPE_window,NULL);
视图=构建视图();
gtk_容器添加(gtk_容器(窗口),视图);
GtkStyle*style=gtk_小部件_获取_样式(视图);
GtkStyleClass*klass=GTK_STYLE_GET_CLASS(STYLE);
klass->draw\u expander=draw\u expander;
gtk_小部件_全部显示(窗口);
gtk_main();
返回0;
}

也许你应该试着切换到一个主题,以你想要的方式绘制扩展器,因为我很确定,如果你“强迫”你的一些用户认可三角形是绘制扩展器的唯一方式,并且拒绝他们改变这一点,他们可能会觉得有点粗鲁

这就是主题设计的目的——这样每个人都可以拥有她想要的外观

嗯,无论如何,不幸的是,实际上GTK正在从版本2过渡到版本3,因此根据您使用的版本,您必须覆盖另一个信号

在GTK3中应该更容易一点,因为您已经在“draw”信号中获得了开罗上下文,但是在GTK2中也可以,这里您必须使用“expose event”信号

这里的示例是如何使用GTK版本2执行此操作的一个片段。因为我不是真正的艺术家,它看起来可能不太好看,但我相信你会想出一个很好的设计

。。。啊,别忘了根据它的状态改变它的绘画方式

#include <gtk/gtk.h>
#include <cairo.h>


gboolean draw (GtkWidget *widget, GdkEventExpose *event, gpointer data) {

  cairo_t *cr;

  cr = gdk_cairo_create (widget->window);

  cairo_set_source_rgb(cr, 0, 0, 0);

  cairo_move_to (cr, 0, 0);
  cairo_line_to (cr, 0, 10);
  cairo_line_to (cr, 10, 5);
  cairo_close_path (cr);

  cairo_stroke  (cr);

  return TRUE;
}


int main (int argc, char *argv[]) {
  gtk_init (&argc, &argv);

  GtkWidget *window;
  GtkWidget *expander;


  window = g_object_new (GTK_TYPE_WINDOW, NULL);  
  expander = g_object_new (GTK_TYPE_EXPANDER, NULL);
  gtk_container_add (GTK_CONTAINER (window), expander);

  g_signal_connect (expander, "expose-event", draw, NULL);

  gtk_widget_show_all (window);
  gtk_main ();

  return 0;
}
#包括
#包括
gboolean绘图(GtkWidget*小部件、GdkEventExpose*事件、gpointer数据){
开罗*cr;
cr=gdk\u cairo\u create(小部件->窗口);
cairo\u set\u source\u rgb(cr,0,0,0);
开罗移动到(cr,0,0);
开罗线(cr,0,10);
开罗线(cr,10,5);
开罗路(cr);
脑卒中(cr);
返回TRUE;
}
int main(int argc,char*argv[]){
gtk_init(&argc,&argv);
GtkWidget*窗口;
GtkWidget*扩展器;
window=g_object_new(GTK_TYPE_window,NULL);
expander=g_object_new(GTK_TYPE_expander,NULL);
gtk_容器添加(gtk_容器(窗口)、扩展器);
g_信号_连接(扩展器,“暴露事件”,绘图,空);
gtk_小部件_全部显示(窗口);
gtk_main();
返回0;
}
编辑:

正如我所看到的,您似乎不想只更改一个实例的外观,而是要更改所有扩展器的外观。要完成此操作,您必须覆盖默认处理程序,如下所示:

#include <gtk/gtk.h>
#include <cairo.h>


gboolean draw (GtkWidget *widget, GdkEventExpose *event) {

  cairo_t *cr;

  cr = gdk_cairo_create (widget->window);

  cairo_set_source_rgb(cr, 0, 0, 0);

  cairo_move_to (cr, 0, 0);
  cairo_line_to (cr, 0, 10);
  cairo_line_to (cr, 10, 5);
  cairo_close_path (cr);

  cairo_stroke  (cr);

  return TRUE;
}


int main (int argc, char *argv[]) {
  gtk_init (&argc, &argv);

  GtkWidget *window;
  GtkWidget *expander;
  GtkWidgetClass *klass;

  window = g_object_new (GTK_TYPE_WINDOW, NULL);  
  expander = g_object_new (GTK_TYPE_EXPANDER, NULL);
  gtk_container_add (GTK_CONTAINER (window), expander);

  klass = g_type_class_peek (GTK_TYPE_EXPANDER);
  klass->expose_event =  draw;

  gtk_widget_show_all (window);
  gtk_main ();

  return 0;
}
#包括
#包括
gboolean绘图(GtkWidget*小部件,GdkEventExpose*事件){
开罗*cr;
cr=gdk\u cairo\u create(小部件->窗口);
cairo\u set\u source\u rgb(cr,0,0,0);
开罗移动到(cr,0,0);
开罗线(cr,0,10);
开罗线(cr,10,5);
开罗路(cr);
脑卒中(cr);
返回TRUE;
}
int main(int argc,char*argv[]){
gtk_init(&argc,&argv);
GtkWidget*窗口;
GtkWidget*扩展器;
GtkWidgetClass*klass;
window=g_object_new(GTK_TYPE_window,NULL);
expander=g_object_new(GTK_TYPE_expander,NULL);
gtk_容器添加(gtk_容器(窗口)、扩展器);
klass=g_型_类_peek(GTK_型_膨胀机);
klass->expose_event=draw;
gtk_小部件_全部显示(窗口);
gtk_main();
返回0;
}

非常感谢您的回复!不幸的是,我不知道如何连接到扩展器的绘图信号,因为我无法将扩展器小部件与GtkTreeView小部件隔离。我有一个现有的GtkTreeView小部件,我需要更改它使用的扩展器的外观。你知道怎么做吗?我不知道在GTK 3中如何处理这个问题,因为旧的样式系统似乎被标记为不推荐使用,但在GTK 2中,你必须选择与视图相关联的样式并覆盖draw_expander方法。只需看一下上面的示例如何执行此操作谢谢你的帮助。有趣的是,您的解决方案与我在问题中提出的几乎完全相同,但设置draw_expander函数的时间却完全不同——在我所有的小部件修改之后,我将(GTK_STYLE_GET_类(pTreeView->STYLE))->draw_expander=my_draw_expander调用移动到了,并且成功了!再次感谢,干得好。