如何使用GTK + / Cairo旋转图像

我有一个简单的应用程序,应该使用GTK+Cairo每隔x毫秒旋转一个装饰轮。 我在下面有一些代码从计时器调用cairo_rotate() 。 但是,图像不会改变。 我是否必须使图像无效以使曝光事件触发? 我对开罗这么新,一个简单的例子演示如何在GTK+使用Cairo旋转图像将受到高度赞赏。

 #include  #include  cairo_surface_t *image; cairo_t *cr; gboolean rotate_cb( void ) { cairo_rotate (cr, 1); //cairo_paint(cr); printf("rotating\n"); return( TRUE ); } static gboolean on_expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data) { cr = gdk_cairo_create (widget->window); cairo_set_source_surface(cr, image, 0, 0); cairo_paint(cr); printf("Paint\n"); //cairo_destroy(cr); return FALSE; } int main(int argc, char *argv[]) { GtkWidget *window; image = cairo_image_surface_create_from_png("wheel.png"); gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); g_signal_connect(window, "expose-event", G_CALLBACK (on_expose_event), NULL); g_signal_connect(window, "destroy", G_CALLBACK (gtk_main_quit), NULL); gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); gtk_window_set_default_size(GTK_WINDOW(window), 500, 500); gtk_widget_set_app_paintable(window, TRUE); gtk_widget_show_all(window); g_timeout_add(500, (GSourceFunc) rotate_cb, NULL); gtk_main(); cairo_destroy(cr); cairo_surface_destroy(image); return 0; } 

您需要将旋转存储在变量中并放入cairo_rotate(cr,rotation_amt); 在绘制之前调用on_expose_event方法。

如果图像居中,也可以转换到窗口的中心,旋转和平移,使轮子围绕它的中心旋转。

 cairo_translate(cr, width / 2.0, height / 2.0); cairo_rotate(cr, rotation_amt); cairo_translate(cr, - image_w / 2.0, - image_h / 2.0); cairo_set_source_surface(cr, image, 0, 0); cairo_paint(cr); 

我希望是对的。

正如ptomato所说,你需要通过调用rotate_cb中的gtk_widget_queue_draw来使绘图表面无效。 保持开罗背景的全局变量是多余的。 图像不会旋转,因为新创建的上下文加载了单位矩阵,并且所有先前的转换都被重置。

在cairo邮件列表的帮助下,这是一个有效的例子。 我正在为那些可能觉得有用的人分享这个。

 #include  #include  #include  #include  cairo_surface_t *image; cairo_t *cr; gdouble rotation = 0; GtkWidget *window; gint image_w, image_h; double DegreesToRadians( int degrees ); double DegreesToRadians( int degrees ) { return((double)((double)degrees * ( M_PI/180 ))); } gboolean rotate_cb( void *degrees ) { // Any rotation applied to cr here will be lost, as we create // a new cairo context on every expose event //cairo_rotate (cr, 4); rotation += DegreesToRadians((*(int*)(degrees))); //cairo_paint(cr); // printf("rotating\n"); // Tell our window that it should repaint itself (ie. emit an expose event) gtk_widget_queue_draw(window); return( TRUE ); } static gboolean on_expose_event(GtkWidget *widget, GdkEventExpose *event,gpointer data) { // Make sure our window wasn't destroyed yet // (to silence a warning) g_return_if_fail(GTK_IS_WIDGET(widget)); cr = gdk_cairo_create (widget->window); // We need to apply transformation before setting the source surface // We translate (0, 0) to the center of the screen, // so we can rotate the image around its center point, // not its upper left corner cairo_translate(cr, image_w/2, image_h/2); cairo_rotate(cr, rotation); cairo_set_source_surface(cr, image, -image_w/2, -image_h/2); // We need to clip around the image, or cairo will paint garbage data //cairo_rectangle(cr, -image_w/2, -image_h/2, image_w, image_h); //cairo_clip(cr); cairo_paint(cr); //printf("Paint\n"); cairo_destroy(cr); return FALSE; } int main(int argc, char *argv[]) { int degrees = 10, speed = 125; image = cairo_image_surface_create_from_png("wheel.png"); image_w = cairo_image_surface_get_width(image); image_h = cairo_image_surface_get_height(image); gtk_init(&argc, &argv); if( argc == 3 ) { degrees = atoi(argv[1]); speed = atoi(argv[2]); } window = gtk_window_new(GTK_WINDOW_TOPLEVEL); g_signal_connect(window, "expose-event", G_CALLBACK (on_expose_event), NULL); g_signal_connect(window, "destroy", G_CALLBACK (gtk_main_quit), NULL); gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); gtk_window_set_default_size(GTK_WINDOW(window), image_w, image_h); gtk_widget_set_app_paintable(window, TRUE); gtk_widget_show_all(window); g_timeout_add(speed, (GSourceFunc) rotate_cb, (void *)&degrees); gtk_main(); cairo_surface_destroy(image); return 0; }