Gtk3 和 cairo g_timeout_add 不起作用
Posted
技术标签:
【中文标题】Gtk3 和 cairo g_timeout_add 不起作用【英文标题】:Gtk3 and cairo g_timeout_add doesn't work 【发布时间】:2018-02-16 18:45:33 【问题描述】:我用 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();
【问题讨论】:
【参考方案1】:为什么会发生和
这是由 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()
来确定你必须在哪里绘制怎么样? IE。而不是假设您的绘图速度足够快,您只需在每次绘图时计算当前的图形状态。
【讨论】:
非常感谢,我明白了!【参考方案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()
函数),所以超时可能无法跟上 1 毫秒的滴答声,当然不应该依赖于精确的计时。
【讨论】:
但是它的工作速度要慢得多,它不会延迟 1 毫秒或 5 毫秒,它的工作速度至少要慢 50 倍。这不正常。以上是关于Gtk3 和 cairo g_timeout_add 不起作用的主要内容,如果未能解决你的问题,请参考以下文章