📄 x2152.html
字号:
...);</PRE></TD></TR></TABLE><P>创建一个新信号。参数是:</P><P></P><UL><LI><P> <TTCLASS="LITERAL">name</TT>:信号的名称。</P></LI><LI><P> <TTCLASS="LITERAL">run_type</TT>:设定是在用户处理函数之前还是之后运行默认处理函数。该值通常会是 <TTCLASS="LITERAL">GTK_RUN_FIRST</TT> 或 <TTCLASS="LITERAL">GTK_RUN_LAST</TT>,虽然也有其它值。</P></LI><LI><P> <TTCLASS="LITERAL">object_type</TT>:发出该信号的对象的ID。(也可能是子对象的ID。)</P></LI><LI><P> <TTCLASS="LITERAL">function_offset</TT>:类结构指针相对于默认处理函数的偏移量。</P></LI><LI><P> <TTCLASS="LITERAL">marshaller</TT>:一个用于调用信号处理函数的函数。对于除了发出信号的对象和用户数据外没有其它的参数的信号处理函数,我们可以使用事先提供的 marshaller 函数 <TTCLASS="LITERAL">gtk_signal_default_marshaller</TT>。</P></LI><LI><P> <TTCLASS="LITERAL">return_val</TT>:返回值的类型。</P></LI><LI><P> <TTCLASS="LITERAL">nparams</TT>:信号处理函数的参数个数 (除了前面提到的"发出信号的对象"和"用户数据"这两个默认参数 )</P></LI><LI><P> <TTCLASS="LITERAL">...</TT>:参数的数据类型。</P></LI></UL><P>当指定类型时,要用到 <TTCLASS="LITERAL">GtkType</TT> 枚举类型:</P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">typedef enum{ GTK_TYPE_INVALID, GTK_TYPE_NONE, GTK_TYPE_CHAR, GTK_TYPE_BOOL, GTK_TYPE_INT, GTK_TYPE_UINT, GTK_TYPE_LONG, GTK_TYPE_ULONG, GTK_TYPE_FLOAT, GTK_TYPE_DOUBLE, GTK_TYPE_STRING, GTK_TYPE_ENUM, GTK_TYPE_FLAGS, GTK_TYPE_BOXED, GTK_TYPE_FOREIGN, GTK_TYPE_CALLBACK, GTK_TYPE_ARGS, GTK_TYPE_POINTER, /* 如果下面两个最终能被删除就好了。*/ GTK_TYPE_SIGNAL, GTK_TYPE_C_CALLBACK, GTK_TYPE_OBJECT} GtkFundamentalType;</PRE></TD></TR></TABLE><P><TTCLASS="LITERAL">gtk_signal_new()</TT> 返回一个能识别信号的唯一整数,我们把它存储在 <TTCLASS="LITERAL">tictactoe_signals</TT> 数组里,并用枚举值来做索引。(依照惯例,枚举成员是信号的名称,且是大写的,但在这里会与 <TTCLASS="LITERAL">TICTACTOE()</TT> 宏冲突,因此我们用 <TTCLASS="LITERAL">TICTACTOE_SIGNAL</TT> 代替。)</P><P>创建了信号之后,我们需要让 GTK 将我们的信号和 Tictactoe 类联系起来。调用 <TTCLASS="LITERAL">gtk_object_class_add_signals()</TT> 函数可以做这件事。然后我们把指向 "tictactoe" 信号默认处理函数的指针设为 NULL,表明没有默认的动作。</P></DIV><DIVCLASS="SECT2"><H2CLASS="SECT2"><ANAME="AEN2242"><TTCLASS="LITERAL">_init()</TT> 函数</H2><P>每个构件类也需要一个初始化对象结构的函数。通常,该函数有个相当有限的任务,就是设置结构成员为缺省值。对于复合构件,这个函数还创建成分(component)构件。</P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">static voidtictactoe_init (Tictactoe *ttt){ GtkWidget *table; gint i,j; table = gtk_table_new (3, 3, TRUE); gtk_container_add (GTK_CONTAINER(ttt), table); gtk_widget_show (table); for (i=0;i<3; i++) for (j=0;j<3; j++) { ttt->buttons[i][j] = gtk_toggle_button_new (); gtk_table_attach_defaults (GTK_TABLE(table), ttt->buttons[i][j], i, i+1, j, j+1); gtk_signal_connect (GTK_OBJECT (ttt->buttons[i][j]), "toggled", GTK_SIGNAL_FUNC (tictactoe_toggle), ttt); gtk_widget_set_size_request (ttt->buttons[i][j], 20, 20); gtk_widget_show (ttt->buttons[i][j]); }}</PRE></TD></TR></TABLE></DIV><DIVCLASS="SECT2"><H2CLASS="SECT2"><ANAME="AEN2247">其余的...</H2><P>另外还有一个函数每个构件(除了基本的构件类型,如 Bin 不能实例化)都需要 - 被用户调用以创建一个该类型的对象的函数。这个调用通常是 <TTCLASS="LITERAL">WIDGETNAME_new()</TT>。在有些构件里,该函数获得几个参数,依据这几个参数做一些设置,我们的井字游戏构件没有这样做。另外两个函数是针对井字游戏构件的。</P><P><TTCLASS="LITERAL">tictactoe_clear()</TT> 是一个公共函数,它复位构件中的按钮。注意 <TTCLASS="LITERAL">gtk_signal_handler_block_by_data()</TT> 函数用来防止按钮切换信号处理函数被不必要地触发。</P><P><TTCLASS="LITERAL">tictactoe_toggle()</TT> 是当用户点击按钮时调用的信号处理函数。它判断开关按钮中是否出现了导致赢的组合,如果是,则发出 "tictactoe" 信号。</P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">GtkWidget*tictactoe_new (){ return GTK_WIDGET ( gtk_type_new (tictactoe_get_type ()));}void tictactoe_clear (Tictactoe *ttt){ int i,j; for (i=0;i<3;i++) for (j=0;j<3;j++) { gtk_signal_handler_block_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ttt->buttons[i][j]), FALSE); gtk_signal_handler_unblock_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt); }}static voidtictactoe_toggle (GtkWidget *widget, Tictactoe *ttt){ int i,k; static int rwins[8][3] = { { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 }, { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 } }; static int cwins[8][3] = { { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 }, { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 }, { 0, 1, 2 }, { 2, 1, 0 } }; int success, found; for (k=0; k<8; k++) { success = TRUE; found = FALSE; for (i=0;i<3;i++) { success = success && GTK_TOGGLE_BUTTON(ttt->buttons[rwins[k][i]][cwins[k][i]])->active; found = found || ttt->buttons[rwins[k][i]][cwins[k][i]] == widget; } if (success && found) { gtk_signal_emit (GTK_OBJECT (ttt), tictactoe_signals[TICTACTOE_SIGNAL]); break; } }}</PRE></TD></TR></TABLE><P>最后,一个使用我们的井字游戏构件的程序示例:</P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">#include <gtk/gtk.h>#include "tictactoe.h"/* 当赢了时调用 */voidwin (GtkWidget *widget, gpointer data){ g_print ("Yay!\n"); tictactoe_clear (TICTACTOE (widget));}int main (int argc, char *argv[]){ GtkWidget *window; GtkWidget *ttt; gtk_init (&argc, &argv); window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame"); gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC (gtk_exit), NULL); gtk_container_set_border_width (GTK_CONTAINER (window), 10); /* 创建一个新的井字游戏构件 */ ttt = tictactoe_new (); gtk_container_add (GTK_CONTAINER (window), ttt); gtk_widget_show (ttt); /* 连接 "tictactoe" 信号的处理函数 */ gtk_signal_connect (GTK_OBJECT (ttt), "tictactoe", GTK_SIGNAL_FUNC (win), NULL); gtk_widget_show (window); gtk_main (); return 0;}</PRE></TD></TR></TABLE></DIV></DIV><DIVCLASS="NAVFOOTER"><HRALIGN="LEFT"WIDTH="100%"><TABLESUMMARY="Footer navigation table"WIDTH="100%"BORDER="0"CELLPADDING="0"CELLSPACING="0"><TR><TDWIDTH="33%"ALIGN="left"VALIGN="top"><AHREF="x2141.html"ACCESSKEY="P"><<< Previous</A></TD><TDWIDTH="34%"ALIGN="center"VALIGN="top"><AHREF="book1.html"ACCESSKEY="H">Home</A></TD><TDWIDTH="33%"ALIGN="right"VALIGN="top"><AHREF="x2259.html"ACCESSKEY="N">Next >>></A></TD></TR><TR><TDWIDTH="33%"ALIGN="left"VALIGN="top">一个构件的剖析</TD><TDWIDTH="34%"ALIGN="center"VALIGN="top"><AHREF="c2132.html"ACCESSKEY="U">Up</A></TD><TDWIDTH="33%"ALIGN="right"VALIGN="top">从头创建构件</TD></TR></TABLE></DIV></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -