« 前一篇:glib库
后一篇:我和曾经的我们 »

Gtk+应用程序 @ 10/25/2005

学习类
/* 例子开始base.c */
#include <gtk/gtk.h>
int main( int argc, char *argv[] )
{
  GtkWidget *window;
  gtk_init (&argc, &argv);
  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  gtk_widget_show (window);
  gtk_main();
  return(0) ;
}
#########################################################################
编译程序:gcc base.c -o base `gtk-config --cflags --libs`
执行上面创建的应用程序: ./base

gtk_init (&argc, &argv);
所有GTK应用程序都要调用该函数。
它为我们设置一些缺省值例如视觉和颜色映射,然后调用gdk_init(gint *argc, gchar ***arg v )。
这个函数将函数库初始化,设置缺省的信号处理函数,并检查通过命令行传递给应用程序的参数。

window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_widget_show (window);
创建窗口,显示窗口

gtk_main ();
每个Gtk应用程序都要调用的函数。
当程序运行到这里时,Gtk将进入等待状态,等候X事件发生。

#########################################################################
/ *示例开始helloworld helloworld.c */
#include <gtk/gtk.h>
/ *回调函数在本例中忽略了传递给程序的所有参数。下面是回调函数* /
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,主窗口就会用一个"delete_event"信号,然后退出* /
  return(TRUE) ;
}
/* 另一个回调函数*/
void destroy( GtkWidget *widget, gpointer data )
{
  gtk_main_quit() ;
}
int main( int argc, char *argv[] )
{
/* GtkWidget是构件的存储类型* /
  GtkWidget *window;
  GtkWidget *button;
/* 在所有的Gtk应用程序中都应该调用。它的作用是解析由命令行传递
* 进来的参数并将它返回给应用程序* /
  gtk_init(&argc, &argv);
/* 创建一个主窗口* /
  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
/* 当给窗口一个"delete_event"信号时(这个信号是由窗口管
* 理器发出的,通常是在点击窗口标题条右边的"×"按钮,或
* 者在标题条的快捷菜单上选择"close"选项时发出的),我们
* 要求调用上面定义的delete_event()函数传递给这个回调函数
* 的数据是NULL,回调函数会忽略这个参数* /
  gtk_signal_connect (GTK_OBJECT (window), "delete_event",
  GTK_SIGNAL_FUNC (delete_event), NULL);
/* 这里,我们给"destory "事件连接一个信号处理函数,
* 当我们在窗口上调用gtk_widget_destroy()函数
* 或者在"delete_event"事件的回调函数中返回FALSE
* 时会发生这个事件* /
  gtk_signal_connect (GTK_OBJECT (window), "destroy",
  GTK_SIGNAL_FUNC (destroy), NULL);
/* 设置窗口的边框宽度* /
  gtk_container_set_border_width (GTK_CONTAINER (window), 10);
/* 创建一个标题为"Hello World" 的按钮* /
  button = gtk_button_new_with_label ("Hello World");
/* 当按钮接收到"clicked "时,它会调用hello()函数,
* 传递的参数为NULL。函数hello()是在上面定义的* /
  gtk_signal_connect (GTK_OBJECT (button), "clicked",
  GTK_SIGNAL_FUNC (hello), NULL);
/* 当点击按钮时,通过调用gtk_widget_destroy(window)函数销毁窗口。
* 另外,"destory"信号可以从这里发出,也可以来自于窗口管理器* /
  gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
  GTK_SIGNAL_FUNC (gtk_widget_destroy),
  GTK_OBJECT (window));
/* 将按钮组装到窗口中(一个gtk容器中)* /
  gtk_container_add (GTK_CONTAINER (window), button);
/* 最后一步就是显示新创建的构件* /
  gtk_widget_show (button);
/* 显示窗口* /
  gtk_widget_show (window);
/* 所有的GTK应用程序都应该有一个gtk_main()函数。
* 程序的控制权停在这里并等着事件的发生(比如一次按键或鼠标事件)*/
  gtk_main ();
  return(0);
}
/* 示例结束* /
##########################################################################
编译:
gcc -Wall -g helloworld.c -o helloworld `gtk-config --cflags` \
`gtk-config --libs`


Gtk+的信号和回调函数原理
1. 信号(signal)
控制权的传递是使用“信号”的方法。
要让一个按钮执行一个操作,我们需要建立一段信号处理程序,以捕获它的信号,然后调用相应的函数。
这由类似以下所示的函数实现:
gint gtk_signal_connect( GtkObject *object,
                        gchar *name,
                        GtkSignalFunc func,
                        gpointer func_data );
第一个参数* object是将要发出信号的构件,
第二个参数* name是希望捕获的信号的名称,
第三个参数func是捕获信号时要调用的函数,
第四个参数func_data是要传递给函数的用户数据参数。
在第三个参数里指定的函数称为“回调函数” ,它的形式通常是:
void callback_func( GtkWidget *widget,
                    gpointer callback_data );
第一个参数是一个指向发出信号的构件的指针,
第二个参数是一个指向传递给回调函数的用户数据的指针。
gint gtk_signal_connect_object( GtkObject *object,
                                gchar *name,
                                GtkSignalFunc func,
                                GtkObject *slot_object );
gtk_signal_connect_object()跟gtk_signal_connect()一样,除了回调函数仅仅使用一个参数:指向GTK对象的指针。
这样,当用这个函数连接到一个信号时,回调函数将以下面的形式出现:
void callback_func( GtkObject *object);
2. 事件
除了上面描述的信号机制之外,还有一套与X事件机制相对应的事件。
事件的回调函数与信号的回调函数在形式上略有不同:
Void func( GtkWidget *widget,
          GdkEvent *event,
          gpointer callback_data );
Gdk Event是C中的联合体结构,其类型依赖于发生的事件是哪一个事件。
事件结构的另一个组件依赖于事件类型。
将回调函数与一个事件连接起来,需要使用以下形式的函数:
gtk_signal_connect( GTK_OBJECT(button),
      "button_press_event",
                    GTK_SIGNAL_FUNC(button_press_callback),
      NULL );
这个回调函数可以作如下声明:
static gint button_press_callback( GtkWidget *widget,
                                  GdkEventButton *event,
                                  gpointer data );


******************************** Gnome应用程序 ********************************

要用到Gnome库,在代码中只有一些细微的区别。
首先,应该在代码的头部包含gnome.h而不是gtk.h:
#include <gnome.h>
gnome.h头文件中已经包含了gtk.h文件。
其次,应该用gnome_init()函数替换gtk_init()函数。Gnome_init()的声明如下:
gnome_init( const char* app_id,
            const char* app_version,
            int argc,
            char** argv );
gnome_init()函数会在内部调用gtk_init()。
gnome_init()分析命令行参数;它不会改变argc和argv的值。
如果想分析特定的选项,应该使用gnome_init_with_popt_table()函数。
在Gnome应用程序中所有用户可见的字符串都应该为翻译做标记。
翻译是用GNU的gettext实用程序完成的,这称为“国际化”.
在程序的开头,必须调用bindtextdomain()和textdomain() 函数。
这两个函数的调用形式如下:
bindtextdomain (PACKAGE, PACKAGE_LOCALE_DIR);
textdomain (PACKAGE);

******************************** GNU C 编译器 ********************************

gcc [options] [filenames]

gcc -p -g a.c
命令告诉gcc编译a.c时为prof命令建立剖析信息并且把调试信息加入到可执行的文件里。
gcc -pg a.c
命令只告诉gcc为gprof命令建立剖析信息。
gcc a.c
编译不使用任何选项,gcc将会建立(假定编译成功)一个名为a.out的可执行文件
gcc -o a a.out
使用-o编译选项来为即将产生的可执行文件指定一个文件名a来代替a.out。

- c选项告诉gcc 仅把源代码编译为目标代码而跳过汇编和连接的步骤。
缺省时gcc建立的目标代码文件有一个.o 的扩展名。

-S 编译选项告诉gcc在为C代码产生了汇编语言文件后停止编译。
gcc 产生的汇编语言文件的缺省扩展名是.s。

-E选项指示编译器仅对输入文件进行预处理。
1. 优化选项
告诉gcc在耗费更多编译时间和牺牲易调试性的基础上产生更小更快的可执行文件。最典型的是-O和-O2选项。
2. 调试和剖析选项
-g选项告诉gcc产生能被G N U调试器gdb使用的调试信息以便调试程序。
-g和-O联用:同时使用这两个选项时必须清楚所写的某些代码已经在优化时被gcc做了改动。
-pg选项告诉gcc在程序里加入额外的代码,执行时,将产生gprof用的剖析信息以显示程序的耗时情况。

GCC-HOWTO,或者在shell提示符下输入:man gcc这样可以浏览gcc的手册页。

********************************  ********************************

初始化库:
gnome_init()函数的第一个参数是应用程序的名称,第二个参数是代表应用程序版本的字符串。
函数列表: 初始化Gnome
#include <libgnomeui/gnome-init.h>
int gnome_init( const char* app_id,
                const char* app_version,
                int argc,
                char** argv )

用popt分析参数:
用定制的选项添加一个“popt表”。要做到这一点,用gnome_init_with_popt_table()函数代替gnome_init()函数。
函数列表:初始化库,进行参数分析
#include <libgnomeui/gnome-init.h>
int gnome_init_with_popt_table( const char* app_id,
          const char* app_version,
                                int argc,
                                char** argv,
                                const struct poptOption* options,
                                int flags,
                                poptContext* return_ctx )

popt表是一个popt Option结构数组。
下面是其定义:
struct poptOption {
  const char* longName;
  char shortName;
  int argInfo;
  void* arg;
  int val;
  char* descrip;
  char* argDescrip;
};
前二个成员long Name和short ame是选项的长名字和短名字,例如“help”和“h”对应于命令行选项的help和-h。如果只想有一个选项名,它们可以设为NULL和'\0'。
第三个成员arg info告知表输入项是什么类型。
第四个成员arg的意义依赖于arg info成员。
第五个成员val成员是每个成员的标识符。
后两个成员用于对--help选项自动生成输出信息。descrip用于描述选项;argDescrip用于描述选项的参数。

在popt表的开头放一个POPT_ARG_CALLBACK类型条目,会对命令行中的每个选项的信息调用一个用户定义的回调函数。
下面是回调函数应该有的类型:
typedef void (*poptCallbackType)( poptContext con,
                                  enum poptCallbackReason reason,
                                  const struct poptOption* opt,
                                  const char* arg,
                                  void* data );

##########################################################################
这是使用poptGetArgs()完成的。
char** args;
poptContext ctx;
int i;
bindtextdomain (PACKAGE, GNOMELOCALEDIR);
textdomain (PACKAGE);
gnome_init_with_popt_table(APPNAME, VERSION, argc, argv,
options, 0, &ctx);
args = poptGetArgs(ctx);
if (args != NULL)
{
  i = 0;
  while (args[i] != NULL)
  {
      /* Do something with each argument */
      + + i ;
  }
}
poptFreeContext(ctx) ;
##########################################################################

##########################################################################
GnomeHello期望在命令行上输入姓名列表,创建一个对话框向输入的每一个名字打招呼。

下面是GnomeHello用作参数分析的变量和popt表:
static int greet_mode = FALSE;
static char* message = NULL;
static char* geometry = NULL;
struct poptOption options[] = {
  {
  "greet" ,
  ‘g’,
  POPT_ARG_NONE ,
  &greet_mode ,
  0 ,
  N_("Say hello to specific people listed on the command line"),
  NULL
  }
,
  {
  "message " ,
  ‘m’,
  POPT_ARG_STRING ,
  &message ,
  0 ,
  N_("Specify a message other than \"Hello, World!\""),
  N _ ("MESSAGE")
  }
,
  {
  "geometry" ,
  ‘\0’,
  POPT_ARG_STRING,
  &geometry ,
  0 ,
  N_("Specify the geometry of the main window"),
  N _("GEOMETRY")
  }
,
  {
  NULL,
  ‘\ 0’,
  0 ,
  NULL ,
  0 ,
  NULL ,
  NULL
  }
};

下面是main()的第一部分,在这里GnomeHello检验参数是否已经正确组合并装配成一个要欢迎的人员名单列表:

GtkWidget* app;
poptContext pctx;
char** args;
int i;

GSList* greet = NULL;
GnomeClient* client;
bindtextdomain(PACKAGE, GNOMELOCALEDIR);
t e x t d o m a i n ( P A C K A G E ) ;
gnome_init_with_popt_table(PACKAGE, VERSION, argc, argv,options, 0, &pctx);

/* Argument parsing */
args = poptGetArgs(pctx);
if (greet_mode && args)
{
  i = 0;
  while (args[i] != NULL)
  {
      greet = g_slist_prepend(greet, args[i]);
      + + i ;
  }
  /* Put them in order */
  greet = g_slist_reverse(greet);
}
else if (greet_mode && args == NULL)
{
  g_error(_("You must specify someone to greet."));
}
else if (args != NULL)
{
  g_error(_("Command line arguments are only allowed with --greet."));
}
else
{
  g_assert(!greet_mode && args == NULL);
}
poptFreeContext(pctx) ;

##########################################################################

强烈建议将其中的字符串作为翻译标记,这样, gettext脚本能够提取出一个要翻译的字符串表。
宏列表:翻译宏
#include <libgnome/gnome-i18n.h>
_(string)
N_(string)

#include <gnome.h>
static char* a[] =
N_("Translate Me"),
N_("Me Too")
} ;
int main(int argc, char** argv)
{
  bindtextdomain(PACKAGE, GNOMELOCALEDIR);
  textdomain( PACKAGE ) ;
  printf(_("Translated String\n"));
  printf( _ ( a[0] ) ) ;
  printf( _ ( a[1] ) ) ;
  return 0;
}
#########################################################################

########################### 保存配置信息 ###################################

从配置文件获取数据
在配置文件中存储数据
配置文件迭代器
节迭代器
其他的配置文件操作

########################### Gtk+的主循环 ###################################

有关主循环的函数:
#include <gtk/gtkmain.h>
void gtk_main()
void gtk_main_quit()
void gtk_main_iteration()
gint gtk_events_pending()
guint gtk_main_level()

函数列表: 退出函数
#include <gtk/gtkmain.h>
guint gtk_quit_add(guint main_level,GtkFunction function,gpointer data)
void gtk_quit_remove(guint quit_handler_id)
void gtk_quit_remove_by_data(gpointer data)

Timeout函数。
#include <gtk/gtkmain.h>
gint gtk_timeout_add( guint32 interval,GtkFunction function,gpointer data );
停止调用定时函数:
#include <gtk/gtkmain.h>
void gtk_timeout_remove( gint tag );
定期调用的回调函数声明应该是下面的形式:
gint timeout_callback( gpointer data );

函数列表: i d l e函数
#include <gtk/gtkmain.h>
guint gtk_idle_add(GtkFunction function,gpointer data)
void gtk_idle_remove(guint idle_handler_id)
void gtk_idle_remove_by_data(gpointer data)

输入函数回调函数应该是这个样子:
typedef void (*GdkInputFunction) (gpointer data,gint source_fd,GdkInputCondition condition);
函数列表: 输入函数
#include <gdk/gdk.h>
gint gdk_input_add( gint source_fd,
                    GdkInputCondition condition,
                    GdkInputFunction function,
                    gpointer data )
void gdk_input_remove(gint tag)
发布于 10/25/2005 15:50:47 | 评论:0

看帖要回帖...

categories
archives
links
statistics
  • 网志数:1164
  • 评论数:2011