【问题标题】:Update Gtk+2 text view widget from another thread从另一个线程更新 Gtk+2 文本视图小部件
【发布时间】:2019-04-24 13:37:04
【问题描述】:

我正在用 GTK 编写一个聊天客户端。客户端具有主 GTK 循环,以及一个衍生线程,该线程位于 read() 函数处并阻塞,等待来自连接到套接字的文件描述符的输入。

一旦读取函数通过阻塞,它就有一个字符缓冲区的文本,我想将它附加到 GTK 文本视图小部件,但是,这是在一个不同于主 GTK 循环的线程中。

我怎样才能最快速地从其他线程更新 GUI?在 Java 中,我会使用 SwingUtilities.invokeLater(new Runnable()) 方法来导致从主线程调用该方法。我希望在 C 和使用 GTK 中有类似的行为。

这是从新线程调用的函数...

void* messageReceived(void* data)
{
    struct ClientWindow* localVar = (struct ClientWindow*)data;

    while(TRUE)
    {
        char buf[256];
        int bytesRead = read(localVar->socketFileDescriptor, buf, 256);
        GtkTextBuffer* tb = gtk_text_view_get_buffer(GTK_TEXT_VIEW(localVar->chatHistoryTextView));

        GtkTextIter end;

        //This code needs to execute in the main thread
        gtk_text_buffer_get_end_iter(tb, &end);
        gtk_text_buffer_insert(tb, &end, buf, -1);

    }
}

【问题讨论】:

    标签: c multithreading user-interface gtk gtk2


    【解决方案1】:

    我想出的解决方案是使用g_idle_add() 函数。我不知道我是否遗漏了什么,因为解决方案很简单,但没有其他人发现它,所以让我有点担心。

    void* messageReceived(void* data)
    {
        struct ClientWindow* localVar = (struct ClientWindow*)data;
        char* message = NULL;
        int bytesRead = 0;
        do
        {
    
            message = bufferedRead(localVar->socketFileDescriptor, 4, &bytesRead);
    
    
            struct UpdateGUIMessage* updateGui = malloc(sizeof(struct UpdateGUIMessage));
            memset(updateGui, 0, sizeof(struct UpdateGUIMessage));
    
            updateGui->clientWindow = localVar;
            updateGui->message = message;
            updateGui->bytesRead = bytesRead;
    
            g_idle_add(G_SOURCE_FUNC(updateGUI), updateGui);
    
        }while(message != NULL);
    }
    
    
    
    bool updateGUI(void* data)
    {
        struct UpdateGUIMessage* localVar = (struct UpdateGUIMessage*)data;
    
        GtkTextBuffer* tb = gtk_text_view_get_buffer(GTK_TEXT_VIEW(localVar->clientWindow->chatHistoryTextView));
    
        GtkTextIter end;
    
        gtk_text_buffer_get_end_iter(tb, &end);
        gtk_text_buffer_insert(tb, &end, localVar->message, localVar->bytesRead);
    
        free(localVar->message);
        free(data);
    
        return FALSE;       //So it only gets called once and then is removed
    }
    

    【讨论】:

    • 谢谢你!我在 GTK3 中做了非常相似的事情:逐行读取文件,我想将当前行号添加到状态栏。您的代码完美运行。
    • 实际上,这种方法适用于小型工作线程。在较长的工作线程中,UI 更新被推迟。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-05-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-29
    • 1970-01-01
    相关资源
    最近更新 更多