我有一个简单的应用程序,它应该使用GTK+
和Cairo
每隔x毫秒旋转一个装饰轮。我在下面有一些从定时器调用cairo_rotate()
的代码。但是,图像不会改变。我是否必须使图像无效以使曝光事件触发?我是开罗的新手,我们非常感谢您在Cairo
中使用GTK+
演示如何旋转图像的简单示例。
#include <cairo.h>
#include <gtk/gtk.h>
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;
}
答案 0 :(得分:6)
您需要将旋转存储在变量中并放入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来使你的绘图表面无效。保持开罗背景的全局变量是多余的。图像不会旋转,因为新创建的上下文加载了单位矩阵,并且所有先前的转换都被重置。
答案 1 :(得分:3)
在cairo邮件列表的帮助下,这是一个有效的例子。我正在为那些可能觉得有用的人分享这个。
#include <cairo.h>
#include <gtk/gtk.h>
#include <math.h>
#include <stdlib.h>
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 *)°rees);
gtk_main();
cairo_surface_destroy(image);
return 0;
}