我有一个简单的多线程Gtk + 2.0应用程序,它从多个来源(麦克风,网络摄像头,温度传感器)获取数据,并将这些数据显示为屏幕上的图像(网络摄像头帧抓取,麦克风数据表示为示波器渲染,文本等)。

根据我的理解,从Gtk手册和各种文章中只有主处理线程应该使用影响UI的任何Gtk函数/调用。 但是, main()入口点在gtk_main()上阻塞,直到我关闭UI。 除了映射到我点击UI中的按钮或滑块之类的事件处理程序之外,似乎唯一可以选择产生一些pthread并让他们定期对数据进行采样的选项。在UI中更新屏幕上的信息。

我记得做了一些MFC GUI开发很长一段时间,应用了类似的原则:只有一个特定的线程应该更新UI元素。 如何使用Gtk + 2.0在C中完成此操作?

谢谢。

#1楼 票数:8 已采纳

根据文档 ,主even循环可以接受来自不同线程的源:

GMainContext只能在单个线程中运行,但可以将源添加到其中并从其他线程中删除。

因此,您可以通过以下方式在工作线程的UI线程中注入代码:

  1. 创建GSource (例如,通过使用g_idle_source_new );
  2. 使用g-source-set-callback添加要执行的代码;
  3. 使用g_source_attach()将其附加到UI线程上下文。

以下是GTK + 2和GLib> = 2.32的示例程序:

#include <gtk/gtk.h>

#define N_THREADS    100
#define N_ITERATIONS 100

GtkWidget *bar;
GMainContext *context;

static gboolean
update_progress_bar(gpointer user_data)
{
    gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(bar),
                                  g_random_double_range(0, 1));
    return G_SOURCE_REMOVE;
}


static gpointer
thread_func(gpointer user_data)
{
    int n_thread = GPOINTER_TO_INT(user_data);
    int n;
    GSource *source;

    g_print("Starting thread %d\n", n_thread);

    for (n = 0; n < N_ITERATIONS; ++n) {
        /* If you want to see anything you should add a delay
         * to let the main loop update the UI, e.g.:
         * g_usleep(g_random_int_range(1234, 567890));
         */
        source = g_idle_source_new();
        g_source_set_callback(source, update_progress_bar, NULL, NULL);
        g_source_attach(source, context);
        g_source_unref(source);
    }

    g_print("Ending thread %d\n", n_thread);
    return NULL;
}


gint
main(gint argc, gchar *argv[])
{
    GtkWidget *window;
    GThread *thread[N_THREADS];
    int n;

    gtk_init(&argc, &argv);

    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);

    bar = gtk_progress_bar_new();
    gtk_container_add(GTK_CONTAINER(window), bar);

    context = g_main_context_default();

    for (n = 0; n < N_THREADS; ++n)
        thread[n] = g_thread_new(NULL, thread_func, GINT_TO_POINTER(n));

    gtk_widget_show_all(window);
    gtk_main();

    for (n = 0; n < N_THREADS; ++n)
        g_thread_join(thread[n]);

    return 0;
}

#2楼 票数:0

正如你的建议,我会在单独的线程中进行采样。 那么问题是如何更新UI。 我要做的是使用'自管'。 这通常是为了从信号处理程序进行通信,但是当其中一个线程无法等待条件变量时,它在线程之间工作正常。 你在这里做什么是设立一个专门的管道,写一个字符在已获得了数据线的管道,并select()在主程序的管道的读端select()循环。 详细信息: 使用自管道,如何避免事件循环在read()上停顿? -关于它的起源有用的背景在这里

然后,您可以在管道的读取端进行GTK +监听。 因此,你的问题减少到使GTK +对FD上的某些东西做出反应 - 请参见此处 (第一个答案)。

  ask by Cloud translate from so

未解决问题?本站智能推荐:

4回复

使用GTK解决问题

我正在使用GTK构建一个相当简单的C应用程序 ,但必须执行一些阻止IO,这将触发GUI的更新。 为了做到这一点,我在gtk_main()之前开始一个新的pthread : /* global variables */GMainContext *mainc;/* local variables
1回复

当我使用pthread时,新窗口无法打开

我试图制作一个聊天应用程序(IRC),并在工作gui时我无法显示新窗口并在同一时间运行客户端,服务器在控制台上运行完美。 如果我尝试在没有服务器的情况下运行新窗口,它可以正常工作。 我想打开一个新窗口并运行客户端,以便它可以在最近打开的窗口上创建文本。 launchClient也有几个p
1回复

Gtk和C-多线程GUI应用程序和删除全局变量

我有[1]中的示例GTK C应用程序,它可以按预期的方式构建和运行。 我有一个带有+和-按钮的小巧的UI应用程序,用于增加/减少存储在全局变量中的值,并在应用程序中以文本标签的形式呈现它。 我很少使用GUI应用程序,我在C中完成了99%的工作。关于整理本示例并将其用作项目基础,我有两个关键
3回复

使用GTK和C,如何使用按钮开始/停止长时间计算(在单独的线程中)?

使用GTK和C,如何使用按钮开始/停止长时间计算(在单独的线程中)? 我有工作代码可以做到这一点,但我没有信心,这是一个合理的方法(即“正确”)。 我有一个按钮,其标签从“开始”切换到“停止”。 我还有一个全局pthread_t变量来存储一个线程。 我的方法是通过按钮的单击信号处理程序
3回复

我的线程图像生成应用程序如何将其数据获取到gui?

Mandelbrot生成器的慢速多精度实现。 使用POSIX线程进行线程化。 Gtk GUI。 我有点迷路了。 这是我第一次编写线程程序。 我实际上并没有尝试转换它的单线程版本,只是试图实现基本框架。 到目前为止的简要说明: Main创建了watch_render_start
1回复

当我包含-pthreads标志时,为什么tcc无法识别“main”?

我正在尝试使用带有 tcc 的 gtk 3.0 库编译 ac 应用程序。 文档说运行编译的命令是gcc `pkg-config --cflags gtk+-3.0` -o [executable name] [source file] `pkg-config --libs gtk+-3.0` 我正在
2回复

gtk+win32线程

来自http://developer.gnome.org/gdk/unstable/gdk-Threads.html 使用Win32后端,不应该尝试从多个线程进行GDK调用。 但是如何避免冻结界面呢? 例如,我有一个回调按钮,该按钮从主机获取虚拟机名称,并逐行添加到Tree Lis
1回复

创建gtk信号以编辑在其他线程中运行的GtkWidget

我有一个应用程序,该应用程序基本上在终端模式下运行,但是可以在另一个线程中打开它的GUI部分(带有GtkTextView简单窗口可以打印一些消息)。 当主线程中发生某些事件时,我需要手动更新此GtkTextView的内容。 为此,我创建了一个“新消息接收”信号,该信号应将指针传递给带有消息的