以前一直困扰在gtk中使用多线程更新界面的问题,今天终于解决。在写下解决方法,以备后查。
这里以textview中动态显示socket更新数据为例。首先建立socket,然后使用g_idle_add函数添加读取socket函数。在该函数中更新textview中的数据,并且返回一个正值(或者false,用以让gtk循环执行该函数,如果不返回或者返回true则在执行一次后或者返回true后gtk不再执行该函数)。在该函数中利用select解决socket的堵塞问题即可。利用shutdown关闭socket,在idle函数中通过select和recv的函数返回值可以检测socket是否关闭。可以选择在关闭的时候通过g_idle_remove_by_data取消该函数的执行,或者在idle函数中检测socket关闭后返回true。
callback.c
#include "callback.h"
#include "asterisk.h"
void on_connect_clicked(GtkToolItem *button,gpointer data)
{
if(asterisk_in()!=-1)
{
gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(button),GTK_STOCK_DISCONNECT);
g_signal_connect(G_OBJECT(button),"clicked",G_CALLBACK(on_disconnect_clicked),data);
g_idle_add((GSourceFunc)asterisk_refresh_ui,data);
}
}
void on_disconnect_clicked(GtkToolItem *button,gpointer data)
{
if(asterisk_out()==0)
{
GtkTextBuffer *buffer;
gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(button),GTK_STOCK_CONNECT);
g_signal_connect(G_OBJECT(button),"clicked",G_CALLBACK(on_connect_clicked),data);
g_idle_remove_by_data(data);
buffer=gtk_text_view_get_buffer(GTK_TEXT_VIEW(data));
gtk_text_buffer_set_text(buffer,"",-1);
}
}
asterisk.c
#include "asterisk.h"
int sockfd;
int asterisk_in()
{
struct sockaddr_in addr;
char buffer[1024];
bzero(&addr,sizeof(addr));
addr.sin_family=AF_INET;
addr.sin_port=htons(5038);
addr.sin_addr.s_addr=inet_addr("127.0.0.1");
if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
{
perror("create socket");
return -1;
}
if(connect(sockfd,(struct sockaddr *)&addr,sizeof(addr))==-1)
{
perror("connect to socket");
return -1;
}
sprintf(buffer,"Action: login\r\nUsername: ami\r\nSecret: ami\r\n\r\n");
if(send(sockfd,buffer,strlen(buffer),0)!=strlen(buffer))
return -1;
return sockfd;
}
int asterisk_out()
{
close(sockfd);
shutdown(sockfd,2);
return 0;
}
int asterisk_refresh_ui(GtkWidget *textview)
{
char content[BUFSIZ];
fd_set fd;
struct timeval stime={0,0};
GtkTextBuffer *buffer;
GtkTextIter end;
FD_ZERO(&fd);
FD_SET(sockfd,&fd);
if(select(sockfd+1,&fd,NULL,NULL,&stime)>0 && FD_ISSET(sockfd,&fd))
{
bzero(content,sizeof(content));
recv(sockfd,content,sizeof(content),0);
buffer=gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview));
gtk_text_buffer_get_end_iter(buffer,&end);
gtk_text_buffer_insert(buffer,&end,content,-1);
}
return 1;
}