Gtk + 3.0在变量变化时触发的信号

时间:2014-12-18 11:47:46

标签: c++ gtk

我正在尝试使用Gtk 3.0实时显示节点网络。节点网络将实现新节点,并且将在节点之间实时形成新连接。我正在考虑使用一个线程来配置Gtk并开始Gtk的主循环,另一个用于开发节点网络。网络的变量将是全局的,因此网络开发线程和Gtk线程都可以看到网络变量。我将在两侧使用互斥锁以确保同步。

我的Gtk事件处理函数将绘制当前网络,理想情况下,它应该在每次网络更改时被调用(例如,新节点,新连接)。因此,我想知道在Gtk 3.0中是否存在一个解决方案,其中事件处理函数在每次变量发生变化时都会发出信号,比如矢量大小的变化,因为我使用vector来存储节点和连接

我写了一个简单的测试程序,看看我尝试做的事情是否可行。我有一个不断递增整数的线程,而另一个线程执行所有Gtk配置并启动主循环。在下面的代码中,Gtk线程绘制整数的当前值,该值继续递增。但是,此代码是对另一个代码的修改,并且仅在值更改时才会绘制当前值。而且,这段代码不能在Gtk 3.0中编译。有没有办法让这个代码在Gtk 3.0中编译?另外,是否可以仅在整数值改变时使其发出绘图函数?

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

#include <thread>
#include <mutex>
#include <string>

unsigned long long counter;
std::mutex mtx;

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

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, 0.1, 0.1, 0.1);
  cairo_select_font_face(cr, "Purisa", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);

  std::string str;
  mtx.lock();
  str = std::to_string(counter);
  cairo_move_to(cr, 20, 30);
  cairo_show_text(cr, str.c_str());
  mtx.unlock();
  return FALSE;
}

void setupGtk() {

  gtk_init(NULL,NULL);
  GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  g_signal_connect(GTK_WINDOW(window), "destroy",G_CALLBACK(gtk_main_quit), NULL);
  GtkWidget *drawing_area = gtk_drawing_area_new();
  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();
}

void count() {
  while(counter<100000000) {
    mtx.lock();
    counter++;
    mtx.unlock();
  }
}

int main(int argc, char *argv[]) {
  std::thread gtk(setupGtk);
  std::thread process(count);
  gtk.join();
  process.join();
  return 1;
}

1 个答案:

答案 0 :(得分:0)

您需要创建自己的GObject类,并在值更改时向您发出的信号添加信号,或添加属性以表示变量并使用notify信号。

请注意,信号发射不能保证正确穿过线程边界。您需要使用gdk_threads_idle_add()来确保信号在主线程上发送。 如果你的目标只是重绘一个控件,你可以在空闲回调中调用gtk_widget_queue_draw()或相关而不是发出信号。

请注意,空闲回调是异步运行的。如果希望在其他线程继续之前完成回调,则需要自己编写同步方法。

(对不起简短的回答;我很匆忙。)