Gtk3和cairo g_timeout_add不起作用

时间:2018-02-16 18:45:33

标签: c gtk3 cairo

我用gtk3和cairo制作了非常简单的动画。我有g_timeout_add并且它应该每隔1ms调用draw函数,但它调用draw要慢得多。为什么会发生这种情况?如何解决?

#include <gtk/gtk.h>
#include <cairo.h>

gboolean timeout(GtkWidget *widget)
{
    gtk_widget_queue_draw(widget);
    return TRUE;
}

void draw(GtkWidget* widget, cairo_t* cr)
{
    static int width, height,
               posX = 0,
               vX = 1;

    GtkWidget* window = gtk_widget_get_toplevel(widget);
    gtk_window_get_size(GTK_WINDOW(window), &width, &height);

    cairo_set_source_rgb(cr, 0, 0, 0);
    cairo_set_line_width(cr, 1);

    cairo_rectangle(cr, posX, height/2, 1, 1);
    cairo_stroke(cr);

    if(posX + vX >= width || posX + vX == 0)
        vX = -vX;
    posX += vX;
}

int main(int argc, char** argv)
{
    GtkWidget* window;
    GtkWidget* darea;

    gtk_init(&argc, &argv);

    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    darea = gtk_drawing_area_new();

    gtk_container_add(GTK_CONTAINER(window), darea);

    gtk_window_set_default_size(GTK_WINDOW(window), 500, 400);

    g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);
    g_signal_connect(G_OBJECT(darea), "draw", G_CALLBACK(draw), NULL);

    g_timeout_add(1, (GSourceFunc)timeout, window);

    gtk_widget_show_all(window);
    gtk_main();
}

2 个答案:

答案 0 :(得分:2)

根据GLib的g_timeout_add()文档:

Note that timeout functions may be delayed, due to the processing of
other event sources. Thus they should not be relied on for precise
timing. After each call to the timeout function, the time of the next
timeout is recalculated based on the current time and the given
interval (it does not try to 'catch up' time lost in delays).

因为事件循环正在为你的应用程序做其他事情(包括运行你的draw()函数),所以超时可能无法跟上1ms的滴答,当然不应该依赖于精确度定时。

答案 1 :(得分:2)

  

为什么会发生这种情况

Zrax回答了这个问题。我只是想添加一些内容:我在绘图函数中添加了以下内容(并添加了相应的包含)

struct timeval tv;
gettimeofday(&tv, NULL);
printf("%d.%06d\n", (int) tv.tv_sec, (int) tv.tv_usec);

我得到如下输出:

1518869317.202412
1518869317.218970
1518869317.236563
1518869317.253032
1518869317.269721
1518869317.286305

因此,您的绘图函数大约每17毫秒调用一次,或大约每秒60次。

  

我该如何解决?

这提出了一个问题:为什么你想要画得比60 fps更快呢?

如何创建GTimer并使用g_timer_elapsed()来确定您必须绘制的位置?即而不是假设您绘制得足够快,您只需在每次绘制时计算当前图形状态。