Очень простая гладкая анимация с GTK + 2 и Каиром

Я использую gtk + 2.0 и cairo. Я написал простую программу, открывающую окно и перемещающую точку. Простой бильярд, только горизонтальное движение. Это просто тест.

Проблема в том, что это выглядит не так гладко, и я бы спросил, есть ли какой-нибудь эксперт по gtk или cairo, который может проверять наличие ошибок в коде.

Благодарю.

#include <gtk gtk.h="">
#include <math.h>

gboolean timeout(gpointer data)
{
 GtkWidget *widget = GTK_WIDGET(data);
 if (!widget->window) return TRUE;
 gtk_widget_queue_draw(widget);
}

gboolean configure(GtkWidget *widget, GdkEventConfigure *event, gpointer data)
{ 
 return TRUE;
}

****** px = 10;
****** vx = **2**;

gboolean expose(GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
 cairo_t *cr = gdk_cairo_create(widget->window);
 cairo_rectangle(cr, event->area.x, event->area.y, event->area.width, event->area.height);
 cairo_clip(cr);

 cairo_set_source_rgb(cr,1,0,0);
 cairo_arc(cr, px, 100, 6, 0, 2*M_PI);
 cairo_fill(cr);
 cairo_set_source_rgb(cr,0,0,0);
 cairo_destroy(cr);

 if (px <= 3 || px >= 200-3) vx = -vx;
 px += vx;
 return FALSE;
}

int main(int argc, char *argv[])
{
 char *title = "Test";
 int sx = 200;
 int sy = 200;

 gtk_init(NULL,NULL);

 GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 gtk_window_set_title(GTK_WINDOW(window),title);
 gtk_container_set_border_width(GTK_CONTAINER (window), 2);

 g_signal_connect(window, "destroy",G_CALLBACK(gtk_main_quit),&window);
 GtkWidget *drawing_area = gtk_drawing_area_new();
 //g_signal_connect(window,"key-press-event",G_CALLBACK(on_key_press),NULL);

 const GdkColor bianco = { 0, 0xffff, 0xffff, 0xffff };
 const GdkColor nero = { 0, 0x0, 0x0, 0x0 };
 gtk_widget_modify_bg(drawing_area, GTK_STATE_NORMAL, &bianco);

 gtk_widget_set_size_request(drawing_area, sx, sy);

 g_signal_connect(drawing_area,"configure_event",G_CALLBACK(configure), NULL);
 g_signal_connect(drawing_area,"expose_event",G_CALLBACK(expose),NULL);

 gtk_container_add(GTK_CONTAINER(window), drawing_area);
 gtk_widget_show(drawing_area);

 g_timeout_add(**10**, timeout, window);

 if (!GTK_WIDGET_VISIBLE (window))
 gtk_widget_show_all(window);
 else {
 gtk_widget_destroy (window);
 window = NULL;
 }

 gtk_main();
 return 0;
}
</math.h></gtk>
1 ответ

Не так гладко? Ну, с периодом 100 мс, вы рисуете в лучшем случае 10 кадров в секунду, неудивительно, что это не гладко... Вы должны стремиться к 60 кадров в секунду. Кроме того, вы аннулируете весь виджет, вызывая gtk_widget_queue_draw, поэтому ваш вызов cairo_clip в основном бесполезен, так как область отсечения - это весь виджет. Вместо этого вы должны вызвать gtk_widget_queue_draw_area, чтобы ваша область отсечения была полезной и определяла область, сохраняя запись анимации в кадрах n и n-1, поэтому вы перерисовываете обе области, чтобы избежать удаления предыдущего кадра.

В блоге Owen Tailor есть много интересного о восприятии анимации, начиная с этого поста и более поздних:

http://blog.fishsoup.net/2009/05/28/frames-not-idles/

Посмотрите на все посты с цифрами, это золотая жила.

licensed under cc by-sa 3.0 with attribution.