【问题标题】:Drawing area using cairo使用 cairo 的绘图区
【发布时间】: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 的事情。

标签: gtk cpu-usage cairo


【解决方案1】:

g_signal_connect() 函数只是说“当这个事件发生时,执行这个函数”。您可能将它与 gtk_widget_queue_draw() 混淆了,它实际上是导致小部件重绘的函数。

有点违反直觉,信号连接是多对多的。这意味着任意数量的函数都可以连接到同一个信号,并且所有函数都会在该信号发出时被调用。因为你反复调用g_signal_connect(),你得到了到你的绘图函数的多个连接,因此该绘图函数将被多次调用。

因此,您要做的是将g_signal_connect() 移动到您的初始化代码中,因为这通常是信号连接的地方,并且在update_status_led() 中有gtk_widget_queue_draw()(或类似功能)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多