gtk多线程的程序实例
来源:互联网 发布:58上的网络销售可靠吗 编辑:程序博客网 时间:2024/06/16 17:16
采摘处:http://hi.baidu.com/03092049hg/blog/item/e0afaf136e11fb03962b437b.html
#include <gtk/gtk.h>gint test(){ while(1) { gdk_threads_enter(); g_printf("hello\n"); gdk_threads_leave(); }; return TRUE;}gint timeout_callback( gpointer data ){ g_thread_create(test, NULL, FALSE, NULL); return FALSE;}/*这是一个回调函数。data参数在本示例中被忽略。*后面有更多的回调函数示例。*/void hello( GtkWidget *widget, gpointer data ){ g_print ("Hello World\n");}gint delete_event( GtkWidget *widget, GdkEvent *event, gpointer data ){ /*如果你的"delete_event"信号处理函数返回FALSE,GTK会发出"destroy"信号。 *返回TRUE,你不希望关闭窗口。 *当你想弹出“你确定要退出吗?”对话框时它很有用。*/ g_print ("delete event occurred\n"); /*改TRUE为FALSE程序会关闭。*/ return TRUE;}/*另一个回调函数*/void destroy( GtkWidget *widget, gpointer data ){ gtk_main_quit ();}int main( int argc, char *argv[] ){ /* GtkWidget是构件的存储类型*/ GtkWidget *window; GtkWidget *button; if(!g_thread_supported()) g_thread_init(NULL); gdk_threads_init(); /*这个函数在所有的GTK程序都要调用。参数由命令行中解析出来并且送到该程序中*/ gtk_init (&argc, &argv); /*创建一个新窗口*/ window = gtk_window_new (GTK_WINDOW_TOPLEVEL); /*当窗口收到"delete_event"信号(这个信号由窗口管理器发出,通常是“关闭” *选项或是标题栏上的关闭按钮发出的),我们让它调用在前面定义的delete_event()函数。 *传给回调函数的data参数值是NULL,它会被回调函数忽略。*/ g_signal_connect (G_OBJECT (window), "delete_event", G_CALLBACK (delete_event), NULL); /*在这里我们连接"destroy"事件到一个信号处理函数。 *对这个窗口调用gtk_widget_destroy()函数或在"delete_event"回调函数中返回FALSE值 *都会触发这个事件。*/ g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy), NULL); /*创建一个标签为"Hello World"的新按钮。*/ button = gtk_button_new_with_label ("Hello World"); /*当按钮收到"clicked"信号时会调用hello()函数,并将NULL传给 *它作为参数。hello()函数在前面定义了。*/ g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (hello), NULL); /*当点击按钮时,会通过调用gtk_widget_destroy(window)来关闭窗口。 * "destroy"信号会从这里或从窗口管理器发出。*/ g_signal_connect_swapped (G_OBJECT (button), "clicked", G_CALLBACK (gtk_widget_destroy), window); /*把按钮放入窗口(一个gtk容器)中。*/ gtk_container_add (GTK_CONTAINER (window), button); /*最后一步是显示新创建的按钮和窗口*/ gtk_widget_show (button); gtk_widget_show (window); gtk_timeout_add(1, timeout_callback, NULL); /*所有的GTK程序必须有一个gtk_main()函数。程序运行停在这里 *等待事件(如键盘事件或鼠标事件)的发生。*/ gdk_threads_enter(); gtk_main (); gdk_threads_leave(); return 0;} #include <gtk/gtk.h>static GtkWidget *fixed;static GtkWidget *button1;static GtkWidget *button2;int running = 1;void our_thread1(GtkWidget *button){ gint x,y,towards; x=40; y=40; towards=1; while (running) { g_usleep(1); //一定要加 gdk_threads_enter(); //在需要与图形窗口交互的时候加 gtk_fixed_move(GTK_FIXED(fixed),button,x,y); switch(towards) { case 1: x=x+10; if (x==250) towards=2; break; case 2: y=y+10; if (y==250) towards=3; break; case 3: x=x-10; if (x==40) towards=4; break; case 4: y=y-10; if (y==50) towards=5; } gdk_threads_leave(); //搭配上面的 }} void on_begin(GtkWidget* button,gpointer data){ gtk_widget_set_sensitive(button,FALSE); g_thread_create(our_thread1,button1,FALSE,NULL); }void *run_f(GtkWidget *butt,gpointer data){ running = 0;} int main(int argc,char* argv[]){ GtkWidget *window,*view; GtkWidget *vbox,*button,*label; if (!g_thread_supported()) g_thread_init(NULL); gdk_threads_init(); gtk_init(&argc,&argv); window=gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(window),"thread apllication"); g_signal_connect(G_OBJECT(window),"delete_event", G_CALLBACK(gtk_main_quit),NULL); gtk_container_set_border_width(GTK_CONTAINER(window),10); vbox=gtk_vbox_new(FALSE,0); gtk_container_add(GTK_CONTAINER(window),vbox); label=gtk_label_new("Notice! Button is moving"); gtk_box_pack_start(GTK_BOX(vbox),label,FALSE,FALSE,0); view=gtk_viewport_new(NULL,NULL); gtk_box_pack_start(GTK_BOX(vbox),view,FALSE,FALSE,0); fixed=gtk_fixed_new(); gtk_widget_set_usize(fixed,330,330); gtk_container_add(GTK_CONTAINER(view),fixed); button1=gtk_button_new_with_label("1"); gtk_fixed_put(GTK_FIXED(fixed),button1,10,10); button=gtk_button_new_with_label("Start"); gtk_box_pack_start(GTK_BOX(vbox),button,FALSE,FALSE,5); g_signal_connect(G_OBJECT(button),"clicked", G_CALLBACK(on_begin),NULL); // call on_begin GtkWidget *run = gtk_button_new_with_label("stop"); gtk_box_pack_start(GTK_BOX(vbox),run,FALSE,FALSE,5); g_signal_connect(G_OBJECT(run),"clicked", G_CALLBACK(run_f),NULL); // call on_begin gtk_widget_show_all(window); gdk_threads_enter(); gtk_main(); gdk_threads_leave(); return FALSE;}
我们知道glib提供了一个名为g_idle_add的函数,这个函数的功能很容易理解:增加一个空闲任务,让应用程序在空闲时执行指定的函数。这种机制非常有用,如果没有这种机制,很多事情将非常麻烦。它的功能虽然简单,但并不是所有人都知道如何充分发挥它的潜力,这里说说它的几个主要用途吧。
1.在空闲时执行低优先级任务。有的任务优先级比较低,但费耗时间比较长,像屏幕刷新等操作,我们不希望它阻碍当前操作太久,此时可以把它放到空闲任务里去做。实际上GTK+里面也是这样做的,这样可以获得更好的响应性。
2.将同步操作异步化。我们知道在GTK+中,它使用glib的signal作为窗口/控件之间的通信方式,signal的执行是直接调用函数,即整个signal的执行过程是同步完成的。这在多数情况下工作得很好,但有时会出现重入的问题,你调我,我再调你,可能会遇到麻烦。此时我们不得不采用异步方式,而GTK+没有提供像Win32下的PostMessage之类的异步消息,幸好我们可以用g_idle_add函数来模拟。
3.串行化对GUI的访问。在大多数平台下,对GUI资源的访问都是需要串行化的,即在一个GUI应用程序中,只有一个线程可以直接操作GUI资源。这是因为出于效率的考虑,GUI资源是没有加锁保护的,GTK+也是这样的。如果另外一个线程要访问GUI资源,比如要显示一条信息,怎么办呢?这可以通过g_idle_add增加一个空闲任务来实现,idle任务是GUI线程(主线程)中执行的,所以串行了对GUI资源的访问。
这里要注意,idle任务并不是一个独立的线程或者进程,而在是主线程中执行的。所谓空闲是指,当main loop没有其它消息要处理,而且没有更高优先级的工作要做时,就认为处于空闲状态。
网上各种文章都强烈建议,所有对于GUI的操作都在一个线程内完成,其他可能导致阻塞的工作在另外一个线程中。
所以
gdk_threads_enter();
gtk_label_set_text(GTK_LABEL(wbus->time),text);
gdk_threads_leave();
这样的代码应该替换为:
g_idle_add(on_finish, wbus);//子线程中。
gboolean on_finish(gpointer wbus)
{
gtk_label_set_text(GTK_LABEL(wbus->time),text);
return FALSE;
}
- gtk多线程的程序实例
- GTK搭建数采程序的多线程解决方法
- 简单的gtk程序
- gtk 的第一个实例
- gtk带glade的实例
- GTK下的扫雷程序
- GTK下的扫雷程序
- GTK+ 多线程
- gtk的安装和gtk程序的编译
- 关于gtk多线程修改界面的问题
- GTK的非实例化类型-interface
- 【推荐实例】一个典型的多线程的程序
- 一个简单的GTK的例子程序
- 入门多线程服务器程序实例
- 编写GTK程序的技巧....完善中
- ubuntu下GTK+ 应用的入门程序
- 编译一个简单的GTK程序
- 基于GTK的USB视频采集程序
- 研发产品介绍1:开心逍遥笔
- 读取、回收和重用:使用 Excel、XML 和 Java 技术轻松搞定报告在 XML 和 Excel 报告格式之间转换(2)
- 运行游戏时出现0xc000007b错误的解决方法
- Linux ALSA声卡驱动之一:ALSA架构简介
- Spring各个jar文件详解
- gtk多线程的程序实例
- vpn原理及实现--虚拟网卡构建vpn
- Oracle SCN
- JSP验证码刷新无效问题解决
- SQL Server 2005 - 实作CLR存储过程
- Linux ALSA声卡驱动之二:声卡的创建
- 读取、回收和重用:使用 Excel、XML 和 Java 技术轻松搞定报告使用 Java 和 XML 技术读取 Excel 文件并写入新文件(1)
- ArcGIS Server 10.1在Windows Server 2008中的机器名问题
- FetchType.EAGER与FetchType.LAZY的区别