📄 sec-creatingacompositewidget.html
字号:
>The <TTCLASS="LITERAL">WIDGETNAME_class_init()</TT> function initializes the fields ofthe widget's class structure, and sets up any signals for theclass. For our Tictactoe widget it looks like:</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>Our widget has just one signal, the <TTCLASS="LITERAL">tictactoe</TT> signal that isinvoked when a row, column, or diagonal is completely filled in. Notevery composite widget needs signals, so if you are reading this forthe first time, you may want to skip to the next section now, asthings are going to get a bit complicated.</P><P>The function:</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, ...);</PRE></TD></TR></TABLE><P>Creates a new signal. The parameters are:</P><P></P><UL><LI><P> <TTCLASS="LITERAL">name</TT>: The name of the signal.</P></LI><LI><P> <TTCLASS="LITERAL">run_type</TT>: Whether the default handler runs before or afteruser handlers. Usually this will be <TTCLASS="LITERAL">GTK_RUN_FIRST</TT>, or <TTCLASS="LITERAL">GTK_RUN_LAST</TT>,although there are other possibilities.</P></LI><LI><P> <TTCLASS="LITERAL">object_type</TT>: The ID of the object that this signal appliesto. (It will also apply to that objects descendants.)</P></LI><LI><P> <TTCLASS="LITERAL">function_offset</TT>: The offset within the class structure ofa pointer to the default handler.</P></LI><LI><P> <TTCLASS="LITERAL">marshaller</TT>: A function that is used to invoke the signalhandler. For signal handlers that have no arguments other than theobject that emitted the signal and user data, we can use thepre-supplied marshaller function <TTCLASS="LITERAL">gtk_signal_default_marshaller</TT>.</P></LI><LI><P> <TTCLASS="LITERAL">return_val</TT>: The type of the return val.</P></LI><LI><P> <TTCLASS="LITERAL">nparams</TT>: The number of parameters of the signal handler(other than the two default ones mentioned above)</P></LI><LI><P> <TTCLASS="LITERAL">...</TT>: The types of the parameters.</P></LI></UL><P>When specifying types, the <TTCLASS="LITERAL">GtkType</TT> enumeration is used:</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, /* it'd be great if the next two could be removed eventually */ GTK_TYPE_SIGNAL, GTK_TYPE_C_CALLBACK, GTK_TYPE_OBJECT} GtkFundamentalType;</PRE></TD></TR></TABLE><P><TTCLASS="LITERAL">gtk_signal_new()</TT> returns a unique integer identifier for thesignal, that we store in the <TTCLASS="LITERAL">tictactoe_signals</TT> array, which weindex using an enumeration. (Conventionally, the enumeration elementsare the signal name, uppercased, but here there would be a conflictwith the <TTCLASS="LITERAL">TICTACTOE()</TT> macro, so we called it <TTCLASS="LITERAL">TICTACTOE_SIGNAL</TT>instead.</P><P>After creating our signals, we need to tell GTK to associate oursignals with the Tictactoe class. We do that by calling<TTCLASS="LITERAL">gtk_object_class_add_signals()</TT>. We then set the pointer whichpoints to the default handler for the "tictactoe" signal to NULL,indicating that there is no default action.</P></DIV><DIVCLASS="SECT2"><H2CLASS="SECT2"><ANAME="AEN2653">24.3.6. The <TTCLASS="LITERAL">_init()</TT> function</A></H2><P>Each widget class also needs a function to initialize the objectstructure. Usually, this function has the fairly limited role ofsetting the fields of the structure to default values. For compositewidgets, however, this function also creates the component widgets.</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_usize (ttt->buttons[i][j], 20, 20); gtk_widget_show (ttt->buttons[i][j]); }}</PRE></TD></TR></TABLE></DIV><DIVCLASS="SECT2"><H2CLASS="SECT2"><ANAME="AEN2658">24.3.7. And the rest...</A></H2><P>There is one more function that every widget (except for base widgettypes like Bin that cannot be instantiated) needs to have - thefunction that the user calls to create an object of that type. This isconventionally called <TTCLASS="LITERAL">WIDGETNAME_new()</TT>. In somewidgets, though not for the Tictactoe widgets, this function takesarguments, and does some setup based on the arguments. The other twofunctions are specific to the Tictactoe widget. </P><P><TTCLASS="LITERAL">tictactoe_clear()</TT> is a public function that resets all thebuttons in the widget to the up position. Note the use of<TTCLASS="LITERAL">gtk_signal_handler_block_by_data()</TT> to keep our signal handler forbutton toggles from being triggered unnecessarily.</P><P><TTCLASS="LITERAL">tictactoe_toggle()</TT> is the signal handler that is invoked when theuser clicks on a button. It checks to see if there are any winningcombinations that involve the toggled button, and if so, emitsthe "tictactoe" signal.</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>And finally, an example program using our Tictactoe widget:</P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">#include <gtk/gtk.h>#include "tictactoe.h"/* Invoked when a row, column or diagonal is completed */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); /* Create a new Tictactoe widget */ ttt = tictactoe_new (); gtk_container_add (GTK_CONTAINER (window), ttt); gtk_widget_show (ttt); /* And attach to its "tictactoe" signal */ 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%"><TABLEWIDTH="100%"BORDER="0"CELLPADDING="0"CELLSPACING="0"><TR><TDWIDTH="33%"ALIGN="left"VALIGN="top"><AHREF="sec-theanatomyofawidget.html"><<< Previous</A></TD><TDWIDTH="34%"ALIGN="center"VALIGN="top"><AHREF="gtk-tut.html">Home</A></TD><TDWIDTH="33%"ALIGN="right"VALIGN="top"><AHREF="sec-creatingawidgetfromscratch.html">Next >>></A></TD></TR><TR><TDWIDTH="33%"ALIGN="left"VALIGN="top">The Anatomy Of A Widget</TD><TDWIDTH="34%"ALIGN="center"VALIGN="top"><AHREF="ch-writingyourownwidgets.html">Up</A></TD><TDWIDTH="33%"ALIGN="right"VALIGN="top">Creating a widget from scratch</TD></TR></TABLE></DIV> </td> </tr></table> </td> </tr></table></body></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -