从另一个线程更新 Gtk+2 文本视图小部件
Update Gtk+2 text view widget from another thread
我正在用 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);
}
}
我想到的解决方案是使用 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
}
我正在用 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);
}
}
我想到的解决方案是使用 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
}