使用cairo库的cairo_rotate函数对绘制内容进行旋转。但是旋转是围绕原点进行的。以窗口左上角为原点,水平和垂直方向为x、y轴建立的坐标系,这并不是我们想要的效果。我想让图片在窗口中的任意位置进行旋转

我想到的办法就是将绘制的图片移动,使其中心与坐标原点重合,这样就可以实现图片围绕自身进行旋转了,但是这样在窗口中只能显示左上角的一部分旋转图像

这时候就用到cairo_translate这个函数,它的功能就是平移坐标系,将坐标系移动到窗口任何你想显示的位置,在这里就相当于移动图片的位置了!

实现过程
#include <gtk/gtk.h>
#include <cairo.h>
#include <math.h>
guint timer_0;
int angle=0;
gboolean move_point(GtkWidget *widget){
cairo_t *cr;
cr = gdk_cairo_create (widget->window);
// cairo_set_source_rgb(cr, 0, 0, 0);
// cairo_rectangle(cr, 0, 0, 300, 200);
// cairo_stroke_preserve(cr);
// cairo_fill(cr);
GdkPixbuf *src_pixbuf = gdk_pixbuf_new_from_file("bg.jpg", NULL);
// 指定图片大小
GdkPixbuf* dst_pixbuf = gdk_pixbuf_scale_simple(src_pixbuf, 100, 100, GDK_INTERP_BILINEAR);
//平移
cairo_translate(cr,200, 100);
//旋转
cairo_rotate(cr,M_PI*angle/180);
angle++;
if(angle > 360){
angle = 0;
}
// dst_pixbuf作为cr环境的画图原材料,(0, 0):画图的起点坐标
//将图片绘制到坐标原点位置
gdk_cairo_set_source_pixbuf(cr, dst_pixbuf,-gdk_pixbuf_get_width(dst_pixbuf)/2, -gdk_pixbuf_get_height(dst_pixbuf)/2);
cairo_paint(cr); // 绘图
//释放资源
g_object_unref(dst_pixbuf);
g_object_unref(src_pixbuf);
cairo_destroy (cr);
return TRUE;
}
int main(int argc,char* argv[]){
GtkWidget* window;
gtk_init(&argc,&argv);
//创建新窗口
window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window),"Demo");
gtk_window_set_default_size(GTK_WINDOW(window),300,200);
//关联窗口关闭回调函数
g_signal_connect(G_OBJECT(window),"destroy",G_CALLBACK(gtk_main_quit),NULL);
//设置窗口可绘制
gtk_widget_set_app_paintable(window,TRUE);
//显示窗口
gtk_widget_show_all(window);
//启动定时器
timer_0 = g_timeout_add(3,(GSourceFunc)move_point,window);
gtk_main();
return 0;
}
等等,这个球是啥?

原来是画面重复旋转绘制,多个图像重叠造成的。只需要将代码注释部分加上就可以了。每次绘制之前清空屏幕
// cairo_set_source_rgb(cr, 0, 0, 0);
// cairo_rectangle(cr, 0, 0, 300, 200);
// cairo_stroke_preserve(cr);
// cairo_fill(cr);
这是正确的效果

另外,由于重复擦除屏幕与绘制图像,会有闪烁效果,如果要消除这种结果,就需要使用双缓冲技术绘图。
双缓冲的原理就是将图像绘制到缓冲区,再将缓冲区中的图像一次性绘制到窗口中,而不是先擦除窗口再进行绘制,这样就消除了闪烁效果