gtk多线程更新界面

    以前一直困扰在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;
}

你可能感兴趣的:(多线程,socket,gtk)