使用 cairo 绘图到 GTK/GDK 个绘图区
Drawing to GTK/GDK drawing area with cairo
GDK/GTK 中检索 cairo 上下文的机制已损坏 and/or 文档中未正确描述。我试图从按钮按下回调中绘制 GtkDrawingArea 但没有成功。文档建议做
GdkWindow *window = gtk_widget_get_window( widget );
cairo_region_t *cairoRegion = cairo_region_create();
GdkDrawingContext *drawingContext = gdk_window_begin_draw_frame( window, cairoRegion );
cairo_t *cr = gdk_drawing_context_get_cairo_context( drawingContext );
然后使用 cairo 上下文绘图,然后在
上正确结束
gdk_window_end_draw_frame( window, drawingContext );
cairo_region_destroy( cairoRegion );
所有这些似乎都适用于 GTK 3.22.30(和 cairo 1.15.12),但不适用于 GTK 3.24.30(和 cairo 1.16.0)。显然有些东西已经改变了。任何的想法?完整示例如下:
// gcc -Wextra -o hauki hauki.c `pkg-config --cflags --libs gtk+-3.0`
#include <gtk/gtk.h>
gboolean draw_cb(GtkWidget *widget, cairo_t *cr, gpointer data)
{
// This works
cairo_set_source_rgb(cr, 1, 1, 1);
cairo_paint(cr);
return FALSE;
}
gboolean button_cb( GtkWidget *widget, GdkEventButton *event, gpointer object )
{
GdkWindow *window = gtk_widget_get_window( GTK_WIDGET(widget) );
cairo_region_t *cairoRegion = cairo_region_create();
GdkDrawingContext *drawingContext = gdk_window_begin_draw_frame( window, cairoRegion );
cairo_t *cr = gdk_drawing_context_get_cairo_context( drawingContext );
cairo_set_source_rgb(cr, 1, 0, 0);
cairo_move_to(cr, 0, 0);
cairo_line_to(cr, 300, 300);
cairo_stroke(cr);
gdk_window_end_draw_frame( window, drawingContext );
cairo_region_destroy( cairoRegion );
}
int main (int argc, char *argv[])
{
gtk_init( &argc, &argv );
GtkWidget *window = gtk_window_new( GTK_WINDOW_TOPLEVEL );
g_signal_connect( window, "destroy", G_CALLBACK (gtk_main_quit), NULL );
GtkWidget *da = gtk_drawing_area_new();
gtk_widget_add_events( da, GDK_BUTTON_PRESS_MASK );
gtk_widget_set_size_request( da, 300, 300 );
g_signal_connect( da, "draw", G_CALLBACK(draw_cb), NULL );
g_signal_connect( da, "button_press_event", G_CALLBACK(button_cb), NULL );
gtk_container_add( GTK_CONTAINER (window), da );
gtk_widget_show( da );
gtk_widget_show( window );
gtk_main();
return 0;
}
gdk_window_begin_draw_frame()
是一个低级调用,通常只有在您尝试使用 GDK/Cairo 绘制某些内容而不涉及 GTK 时才需要。由于您显然在使用 GTK,因此您不应该使用它。
在 GTK 中使用 Cairo 绘图的方法是使用 GtkDrawingArea
(或者如果您想实现非常自定义的行为:子类化 GtkWidget
并实现您自己的 draw()
vfunc ).正如您已经看到的,它有一个 draw
信号,您可以将回调连接到该信号:该回调将被调用 每次 小部件需要重绘自身。
换句话说,您的绘制回调应该根据特定状态更改其自身的绘制方式:
#include <gtk/gtk.h>
gboolean button_clicked = FALSE;
gboolean draw_cb(GtkWidget *widget, cairo_t *cr, gpointer data)
{
if (button_clicked) {
cairo_set_source_rgb(cr, 1, 0, 0);
cairo_move_to(cr, 0, 0);
cairo_line_to(cr, 300, 300);
cairo_stroke(cr);
}
return FALSE;
}
gboolean button_cb( GtkWidget *widget, GdkEventButton *event, gpointer object )
{
button_clicked = TRUE;
// Explicitly notify the drawing area it should redraw itself
gtk_widget_queue_draw (widget);
}
int main (int argc, char *argv[])
{
gtk_init( &argc, &argv );
GtkWidget *window = gtk_window_new( GTK_WINDOW_TOPLEVEL );
g_signal_connect( window, "destroy", G_CALLBACK (gtk_main_quit), NULL );
GtkWidget *da = gtk_drawing_area_new();
gtk_widget_add_events( da, GDK_BUTTON_PRESS_MASK );
gtk_widget_set_size_request( da, 300, 300 );
g_signal_connect( da, "draw", G_CALLBACK(draw_cb), NULL );
g_signal_connect( da, "button_press_event", G_CALLBACK(button_cb), NULL );
gtk_container_add( GTK_CONTAINER (window), da );
gtk_widget_show( da );
gtk_widget_show( window );
gtk_main();
return 0;
}
GDK/GTK 中检索 cairo 上下文的机制已损坏 and/or 文档中未正确描述。我试图从按钮按下回调中绘制 GtkDrawingArea 但没有成功。文档建议做
GdkWindow *window = gtk_widget_get_window( widget );
cairo_region_t *cairoRegion = cairo_region_create();
GdkDrawingContext *drawingContext = gdk_window_begin_draw_frame( window, cairoRegion );
cairo_t *cr = gdk_drawing_context_get_cairo_context( drawingContext );
然后使用 cairo 上下文绘图,然后在
上正确结束gdk_window_end_draw_frame( window, drawingContext );
cairo_region_destroy( cairoRegion );
所有这些似乎都适用于 GTK 3.22.30(和 cairo 1.15.12),但不适用于 GTK 3.24.30(和 cairo 1.16.0)。显然有些东西已经改变了。任何的想法?完整示例如下:
// gcc -Wextra -o hauki hauki.c `pkg-config --cflags --libs gtk+-3.0`
#include <gtk/gtk.h>
gboolean draw_cb(GtkWidget *widget, cairo_t *cr, gpointer data)
{
// This works
cairo_set_source_rgb(cr, 1, 1, 1);
cairo_paint(cr);
return FALSE;
}
gboolean button_cb( GtkWidget *widget, GdkEventButton *event, gpointer object )
{
GdkWindow *window = gtk_widget_get_window( GTK_WIDGET(widget) );
cairo_region_t *cairoRegion = cairo_region_create();
GdkDrawingContext *drawingContext = gdk_window_begin_draw_frame( window, cairoRegion );
cairo_t *cr = gdk_drawing_context_get_cairo_context( drawingContext );
cairo_set_source_rgb(cr, 1, 0, 0);
cairo_move_to(cr, 0, 0);
cairo_line_to(cr, 300, 300);
cairo_stroke(cr);
gdk_window_end_draw_frame( window, drawingContext );
cairo_region_destroy( cairoRegion );
}
int main (int argc, char *argv[])
{
gtk_init( &argc, &argv );
GtkWidget *window = gtk_window_new( GTK_WINDOW_TOPLEVEL );
g_signal_connect( window, "destroy", G_CALLBACK (gtk_main_quit), NULL );
GtkWidget *da = gtk_drawing_area_new();
gtk_widget_add_events( da, GDK_BUTTON_PRESS_MASK );
gtk_widget_set_size_request( da, 300, 300 );
g_signal_connect( da, "draw", G_CALLBACK(draw_cb), NULL );
g_signal_connect( da, "button_press_event", G_CALLBACK(button_cb), NULL );
gtk_container_add( GTK_CONTAINER (window), da );
gtk_widget_show( da );
gtk_widget_show( window );
gtk_main();
return 0;
}
gdk_window_begin_draw_frame()
是一个低级调用,通常只有在您尝试使用 GDK/Cairo 绘制某些内容而不涉及 GTK 时才需要。由于您显然在使用 GTK,因此您不应该使用它。
在 GTK 中使用 Cairo 绘图的方法是使用 GtkDrawingArea
(或者如果您想实现非常自定义的行为:子类化 GtkWidget
并实现您自己的 draw()
vfunc ).正如您已经看到的,它有一个 draw
信号,您可以将回调连接到该信号:该回调将被调用 每次 小部件需要重绘自身。
换句话说,您的绘制回调应该根据特定状态更改其自身的绘制方式:
#include <gtk/gtk.h>
gboolean button_clicked = FALSE;
gboolean draw_cb(GtkWidget *widget, cairo_t *cr, gpointer data)
{
if (button_clicked) {
cairo_set_source_rgb(cr, 1, 0, 0);
cairo_move_to(cr, 0, 0);
cairo_line_to(cr, 300, 300);
cairo_stroke(cr);
}
return FALSE;
}
gboolean button_cb( GtkWidget *widget, GdkEventButton *event, gpointer object )
{
button_clicked = TRUE;
// Explicitly notify the drawing area it should redraw itself
gtk_widget_queue_draw (widget);
}
int main (int argc, char *argv[])
{
gtk_init( &argc, &argv );
GtkWidget *window = gtk_window_new( GTK_WINDOW_TOPLEVEL );
g_signal_connect( window, "destroy", G_CALLBACK (gtk_main_quit), NULL );
GtkWidget *da = gtk_drawing_area_new();
gtk_widget_add_events( da, GDK_BUTTON_PRESS_MASK );
gtk_widget_set_size_request( da, 300, 300 );
g_signal_connect( da, "draw", G_CALLBACK(draw_cb), NULL );
g_signal_connect( da, "button_press_event", G_CALLBACK(button_cb), NULL );
gtk_container_add( GTK_CONTAINER (window), da );
gtk_widget_show( da );
gtk_widget_show( window );
gtk_main();
return 0;
}