LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 1781|回复: 19

在一个Gtk/Gnome的窗口中显示动态的数据?

[复制链接]
发表于 2004-7-31 14:53:10 | 显示全部楼层 |阅读模式
我希望在一个Gtk/Gnome的窗口中显示动态的数据,比如gnome-system-monitor中可以显示CPU和内存的当前使用状况, 在Gnome面板的右下脚可以显示当前时间,请问编程是怎么实现的呢?

之前,我通过读取/proc/net/dev的方式写了一个测试网络流量的程序,图形界面是用FLTK实现的,在其中用一个循环加sleep>的方式,在循环中不断读取文件并动态显示数据。但这样就不能再接受用户的"stop"的按钮输入了,于是我研究了一下FLTK的源代码,并通过在循环中加入一个Fl::wait()的方法来解决这个问题(FLTK使用Fl::run来运行主循环,并在其中调用Fl::wait().)。但我发现这样的效果不太好,仔细的考虑一下,也觉得不是正确的解决之道,所以即使Gnome也可以用这样的方法,我也认为不妥——但还是想知道Gnome的实现:用gtk_main()开始主循环,其中是不是也有像wait这样的调用呢?

今天看了一下wmmemfree的代码(这是一个dockapps,也是实时显示内存使用状况的),它通过设置定时器和UNIX signal的方式,每隔两秒中调用一个draw_window(), 而其中又有一个update_window(),最终调用XLib来把采集的数据显示出来,而大概实际上就是使用重绘的方式对窗口上的一些区域进行更新:

  1. void update_window()
  2. {
  3. XCopyArea(display, buffer, iconwindow, gc, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0, 0);
  4. XCopyArea(display, buffer, window, gc, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0, 0);
  5. }
复制代码

我目前对于XLib还不了解,但我想知道的是Gnome是不是也可以用这种方式来重绘一些Widget。我通过一本<<Gnome应用程序开发指南>>(John R. Sheets)学习gtk, 但其中主要只是阐述了这个方面的主循环、信号连接和一些Widget, 而在Gtk的文档中似乎也没有看到有关的内容。

有哪位大侠能指教一二,感激不尽!
 楼主| 发表于 2004-8-1 01:12:44 | 显示全部楼层

  1. gint gtk_timeout_add( guint32     interval,
  2.                       GtkFunction function,
  3.                       gpointer    data );
  4. void gtk_timeout_remove( gint tag );
  5. void gtk_timeout_remove( gint tag );
复制代码
发表于 2004-8-1 13:25:28 | 显示全部楼层
用 g_idle_add_full(优先级,你的函数f,参数) 函数,它会在整个gtk_main空闲时调用f。在f中你就可以刷新你的界面了。
 楼主| 发表于 2004-8-1 15:55:22 | 显示全部楼层
对,在GTK+ 2.0 教程中提到了这一点。我现在在考虑的问题是,我要做两个进程,一个不断计算当前时间和提取网络流量的数据,然后通过一个fifo传送到另外一个进程,而这个进程就是我要的这个界面,我考虑它应该定时的读取管道获得这些数据并显示出来。显然前一个进程的FIFO操作应该是NON_BLOCK的,这样我觉得第二个进程的定时用下面的调用应该更好:

  1. gint gdk_input_add( gint              source,
  2.                     GdkInputCondition condition,
  3.                     GdkInputFunction  function,
  4.                     gpointer          data );
复制代码
发表于 2004-8-1 16:49:09 | 显示全部楼层
可以,不过 gdk_input_add is deprecated and should not be used in newly-written code.

更好的是 http://developer.gnome.org/doc/API/2.0/glib/glib-IO-Channels.html
 楼主| 发表于 2004-8-1 22:37:36 | 显示全部楼层
但我现在的一个问题是,第二个进程的读取FIFO应该怎样处理呢?如果是NON_BLOCK,则open()立即返回,那么很可能得不到数据,因为没有办法保证它读取的时候第一个进程正好写;而如果是BLOCK,则进程阻塞,那意味着用户没有办法再在界面上进行操作了?第二个进程调用了execlp()来启动一个GUI。
 楼主| 发表于 2004-8-1 23:02:39 | 显示全部楼层
还有一个想法就是能不能在一个“指定”的描述符上打开FIFO
 楼主| 发表于 2004-8-2 01:18:14 | 显示全部楼层
刚刚尝试了一下,确实不行。不能保证每次都能读到数据,而且得到的数据有问题。看来要使用同步机制了。
发表于 2004-8-2 08:56:44 | 显示全部楼层

  1. gint gdk_input_add( gint              source,
  2.                                 GdkInputCondition condition,
  3.                                 GdkInputFunction  function,
  4.                                 gpointer          data );
复制代码

用了这个以后第一个进程的写操作可以是BLOCK的,
只要你保证GUI的消息循环能及时运行
 楼主| 发表于 2004-8-2 12:05:52 | 显示全部楼层
我想第一个进程不能是BLOCK,否则它又怎样“不断计算当前时间和提取网络流量的数据”呢?我想第二个进程应该也可以是NONBLOCK,可以在一开始打开FIFO,然后用上面的方法提取传递过来的数据。
不过我用Glade生成的一个界面,在main()中调用了一个create_gui()来生成界面,所有控件的指针和信号连接函数都在其中定义,但只返回顶层窗口的指针。现在我如果要在界面上动态显示数据,就势必修改一些部件的内容,也就不得不用到这些指针。这样我可能就必需大动干戈地修改这些代码。有没有一种办法能够直接从顶层窗口获得其下级部件的指针呢--既然它们都被一级级container_add()进来?而且,Gtk本身也是通过运行主循环gtk_main(),从而不断流过所有的部件,进而判断事件和信号应该如何处理的呀。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表