【发布时间】:2016-05-09 13:43:25
【问题描述】:
我正在开发一个使用 GTK3 和 C 模拟 LED 的简单界面。当我收到命令时,“led”会根据命令打开或关闭。我在绘图区域使用 Cairo 来绘制一个代表我的 LED 的圆圈,我正在使用 gtk_widget_queue_draw_area 在我的超时函数中更新屏幕。一段时间后,我的应用程序中的 CPU 使用率增加到 100%。
当我收到命令时,我会调用下面的函数
void update_status_led(int led, int status_led)
{
g_signal_connect(G_OBJECT(darea[led]), "draw", G_CALLBACK(on_draw_event_leds), GINT_TO_POINTER(status_led));
}
所以回调函数“on_draw_event_leds”被调用
gboolean on_draw_event_leds(GtkWidget *widget, cairo_t *cr,
gpointer user_data)
{
set_status_led(cr, GPOINTER_TO_INT(user_data));
return FALSE;
}
所以它调用函数“set_status_led”
void set_status_led(cairo_t *cr, int status)
{
printf("update status led: %d\n", countref++);
cairo_reference(cr);
cairo_set_line_width(cr, 2);
cairo_set_source_rgb(cr, 0, 0, 0);
cairo_arc(cr, 9, 9, 7, 0, 2 * M_PI);
if (status>0)
{
cairo_set_source_rgb(cr, 1, 0, 0); //red
}
else
{
cairo_set_source_rgb(cr, 0, 0, 0); //black
}
cairo_fill(cr);
cairo_stroke(cr);
cairo_destroy(cr);
}
我正在使用 "printf("update status led: %d\n", countref++);"知道我的函数被调用了多少次,我的日志打印在下面
New Connection from 127.0.0.1:34589
1 Command Received
update status led: 6
update status led: 7
1 Command Received
update status led: 8
update status led: 9
update status led: 10
1 Command Received
update status led: 11
update status led: 12
update status led: 13
update status led: 14
1 Command Received
update status led: 15
update status led: 16
update status led: 17
update status led: 18
update status led: 19
1 Command Received
update status led: 20
update status led: 21
update status led: 22
update status led: 23
update status led: 24
update status led: 25
1 Command Received
...
可以看出,我只收到一个命令,我的回调函数 on_draw_event_leds 被多次调用,并且总是增加 1 个调用 之前的 cairo 收到的每个命令都没有被删除,并且 gtk_widget_queue_draw_area 再次渲染它们。
有人可以帮我吗?
谢谢,
【问题讨论】:
-
不确定这是否能解决问题,但您有两个大错误。一、不要打电话
cairo_reference()和cairo_destroy();您不拥有从draw回调中获得的cairo_t。其次,cairo_fill()清除当前路径,因此您的cairo_stroke()什么也不画。请改用ciaro_fill_preserve()。今天晚些时候我会仔细看看。 -
感谢您的帮助,我已解决您所说的问题,但这并没有解决我的问题。我的回调函数仍然被多次调用,并且每个收到的命令再增加 1 个调用。
-
啊,我明白了。您在每次更改时都调用
update_status_led()。g_signal_connect()不会用新的连接替换任何现有连接;相反,它会在现有连接列表中添加一个新连接。因此,您之前连接的所有信号处理程序仍然存在。您需要将代码更改为只调用一次g_signal_connect()。也许将当前状态存储在全局变量或通过最后一个gpointer参数传递给信号函数的共享变量中,并使用gtk_widget_queue_draw()安排重绘。 -
只是好奇,@andlabs,你为什么喜欢在 cmets 中回答?没什么问题,我只是想知道你是否不想要代表什么的。
-
如果我不完全确定发生了什么,不要将答案浪费在实际错误的事情上。 (我认为是这样。这能解决它吗?是的。 好的,这是答案,以更加充实和详细的形式。)也部分来自
winapi标签的习惯。诚然,这个问题应该用我所说的来回答;我也可以写一个更全面的答案,但现在我正忙于 IRL 的事情。