📄 x2152.html
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"><HTML><HEAD><TITLE>创建一个复合构件</TITLE><METANAME="GENERATOR"CONTENT="Modular DocBook HTML Stylesheet Version 1.76b+"><LINKREL="HOME"TITLE="GTK+ 2.0 教程"HREF="book1.html"><LINKREL="UP"TITLE="编写你自己的构件"HREF="c2132.html"><LINKREL="PREVIOUS"TITLE="一个构件的剖析"HREF="x2141.html"><LINKREL="NEXT"TITLE="从头创建构件"HREF="x2259.html"></HEAD><BODYCLASS="SECT1"BGCOLOR="#FFFFFF"TEXT="#000000"LINK="#0000FF"VLINK="#840084"ALINK="#0000FF"><DIVCLASS="NAVHEADER"><TABLESUMMARY="Header navigation table"WIDTH="100%"BORDER="0"CELLPADDING="0"CELLSPACING="0"><TR><THCOLSPAN="3"ALIGN="center">GTK+ 2.0 教程</TH></TR><TR><TDWIDTH="10%"ALIGN="left"VALIGN="bottom"><AHREF="x2141.html"ACCESSKEY="P"><<< Previous</A></TD><TDWIDTH="80%"ALIGN="center"VALIGN="bottom">编写你自己的构件</TD><TDWIDTH="10%"ALIGN="right"VALIGN="bottom"><AHREF="x2259.html"ACCESSKEY="N">Next >>></A></TD></TR></TABLE><HRALIGN="LEFT"WIDTH="100%"></DIV><DIVCLASS="SECT1"><H1CLASS="SECT1"><ANAME="SEC-CREATINGACOMPOSITEWIDGET">创建一个复合构件</H1><DIVCLASS="SECT2"><H2CLASS="SECT2"><ANAME="AEN2154">介绍</H2><P>你可能乐于创建这样一种类型的构件,它仅仅是其它 GTK 构件的一个组合。为组装用户界面元素以重复使用提供了便利的方法。在标准发布中的文件选择和颜色选择构件就是这种类型构件的示例。</P><P>我们将要在这一节创建一个井字游戏构件,一个 3X3 的开关按钮矩阵,当同一列、同一行或是对角线的所有三个按钮都被按下时触发一个信号。</P><P><SPANCLASS="INLINEMEDIAOBJECT"><IMGSRC="images/tictactoe.png"></SPAN></P></DIV><DIVCLASS="SECT2"><H2CLASS="SECT2"><ANAME="AEN2162">选择一个父类</H2><P>通常,一个复合构件的父类是一个容纳复合构件的所有元素的容器类。例如,文件选择构件的父类就是对话框类。因为我们的按钮排列在一个表中,看起来应该让表类作为我们的父类。但不幸的是,这样无法工作。构件的创建分为两个函数 - 一个用户调用的 <TTCLASS="LITERAL">WIDGETNAME_new()</TT> 函数,另一个是 <TTCLASS="LITERAL">WIDGETNAME_init()</TT> 函数作基本的初始化构件的工作,它不使用传递给 <TTCLASS="LITERAL">_new()</TT> 函数的参数。子构件只调用父构件的 <TTCLASS="LITERAL">_init</TT> 函数。但是这个分工不能在表中正常工作,因为创建表时需要知道表的行数和列数。除非我们想重新实现 <TTCLASS="LITERAL">gtk_table_new()</TT> 的大多数功能,我们最好避免从表派生构件。由于这个原因,代替表,我们从纵向盒派生构件,然后把表放入纵向盒。</P></DIV><DIVCLASS="SECT2"><H2CLASS="SECT2"><ANAME="AEN2170">头文件</H2><P>每个构件类有一个头文件,该头文件用于声明构件的对象、类结构和公共函数。有两个特性是值得指出的。为避免重复定义,我们把整个头文件放入如下语句里:</P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">#ifndef __TICTACTOE_H__#define __TICTACTOE_H__...#endif /* __TICTACTOE_H__ */</PRE></TD></TR></TABLE><P>并且让 C++ 程序也能包含该头文件:</P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">#ifdef __cplusplusextern "C" {#endif /* __cplusplus */...#ifdef __cplusplus}#endif /* __cplusplus */</PRE></TD></TR></TABLE><P>在我们的头文件里,和函数、结构一起声明的还有三个标准宏。 <TTCLASS="LITERAL">TICTACTOE(obj)</TT>, <TTCLASS="LITERAL">TICTACTOE_CLASS(class)</TT> 和 <TTCLASS="LITERAL">IS_TICTACTOE(obj)</TT>,这三个宏分别是将指针转换为指向对象、类的指针和检测一个对象是否是一个井字游戏构件。</P><P>下面是全部的头文件:</P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING"> /* GTK - GIMP工具包 * 版权 (C) 1995-1997 Peter Mattis, Spencer Kimball 和 Josh MacDonald 所有 * * 本程序是自由软件。你可以在自由软件基金发布的 GNU GPL 的条款下重新分发 * 或修改它。GPL 可以使用版本 2 或(由你选择)任何随后的版本。 * * 本程序分发的目的是它可能对其他人有用,但不提供任何的担保,包括隐含的 * 和适合特定用途的保证。请查阅GNU通用公共许可证获得详细的信息。 * * 你应该已经随该软件一起收到一份GNU通用公共许可。如果还没有,请写信给 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */#ifndef __TICTACTOE_H__#define __TICTACTOE_H__#include <gdk/gdk.h>#include <gtk/gtkvbox.h>#ifdef __cplusplusextern "C" {#endif /* __cplusplus */#define TICTACTOE(obj) GTK_CHECK_CAST (obj, tictactoe_get_type (), Tictactoe)#define TICTACTOE_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, tictactoe_get_type (), TictactoeClass)#define IS_TICTACTOE(obj) GTK_CHECK_TYPE (obj, tictactoe_get_type ())typedef struct _Tictactoe Tictactoe;typedef struct _TictactoeClass TictactoeClass;struct _Tictactoe{ GtkVBox vbox; GtkWidget *buttons[3][3];};struct _TictactoeClass{ GtkVBoxClass parent_class; void (* tictactoe) (Tictactoe *ttt);};GtkType tictactoe_get_type (void);GtkWidget* tictactoe_new (void);void tictactoe_clear (Tictactoe *ttt);#ifdef __cplusplus}#endif /* __cplusplus */#endif /* __TICTACTOE_H__ */ </PRE></TD></TR></TABLE></DIV><DIVCLASS="SECT2"><H2CLASS="SECT2"><ANAME="AEN2182"><TTCLASS="LITERAL">_get_type()</TT> 函数</H2><P>现在,我们继续实现我们的构件。<TTCLASS="LITERAL">WIDGETNAME_get_type()</TT> 函数是每个构件的核心函数。当第一次调用时,该函数告之 GTK 这个构件类并得到一个能唯一识别该构件类的 ID。之后的调用,只返回这个ID。</P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">GtkTypetictactoe_get_type (){ static guint ttt_type = 0; if (!ttt_type) { GtkTypeInfo ttt_info = { "Tictactoe", sizeof (Tictactoe), sizeof (TictactoeClass), (GtkClassInitFunc) tictactoe_class_init, (GtkObjectInitFunc) tictactoe_init, (GtkArgSetFunc) NULL, (GtkArgGetFunc) NULL }; ttt_type = gtk_type_unique (gtk_vbox_get_type (), &ttt_info); } return ttt_type;}</PRE></TD></TR></TABLE><P>GtkTypeInfo 结构定义如下:</P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">struct _GtkTypeInfo{ gchar *type_name; guint object_size; guint class_size; GtkClassInitFunc class_init_func; GtkObjectInitFunc object_init_func; GtkArgSetFunc arg_set_func; GtkArgGetFunc arg_get_func;};</PRE></TD></TR></TABLE><P>这个结构的域很形象。我们在这里忽略 <TTCLASS="LITERAL">arg_set_func</TT> 和 <TTCLASS="LITERAL">arg_get_func</TT> 这两个域:它们很重要,但大部分还未实现,它们允许解释性语言方便地设置构件的属性。一旦 GTK 正确的填充了该结构,它就知道了如何去创建一个特殊构件类型的对象。</P></DIV><DIVCLASS="SECT2"><H2CLASS="SECT2"><ANAME="AEN2193"><TTCLASS="LITERAL">_class_init()</TT> 函数</H2><P><TTCLASS="LITERAL">WIDGETNAME_class_init()</TT>函数初始化构件类结构的域,并为类设置任何信号。我们的井字游戏构件是这样的:</P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">enum { TICTACTOE_SIGNAL, LAST_SIGNAL};static gint tictactoe_signals[LAST_SIGNAL] = { 0 };static voidtictactoe_class_init (TictactoeClass *class){ GtkObjectClass *object_class; object_class = (GtkObjectClass*) class; tictactoe_signals[TICTACTOE_SIGNAL] = gtk_signal_new ("tictactoe", GTK_RUN_FIRST, object_class->type, GTK_SIGNAL_OFFSET (TictactoeClass, tictactoe), gtk_signal_default_marshaller, GTK_TYPE_NONE, 0); gtk_object_class_add_signals (object_class, tictactoe_signals, LAST_SIGNAL); class->tictactoe = NULL;}</PRE></TD></TR></TABLE><P>我们的构件只有一个<TTCLASS="LITERAL">tictactoe</TT>信号,当连成一行、一列或一个对角线时,该信号被触发。并不是每个复合构件都需要信号,因此当你第一次阅读这节时,可以跳过看下一节,因为这一节对初学者有点难。</P><P>函数:</P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">gint gtk_signal_new( const gchar *name, GtkSignalRunType run_type, GtkType object_type, gint function_offset, GtkSignalMarshaller marshaller, GtkType return_val, guint nparams,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -