|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>Creating a Composite widget
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
NAME="GENERATOR"
|
|
Packit |
98cdb6 |
CONTENT="Modular DocBook HTML Stylesheet Version 1.79">
|
|
Packit |
98cdb6 |
REL="HOME"
|
|
Packit |
98cdb6 |
TITLE="GTK+ 2.0 Tutorial"
|
|
Packit |
98cdb6 |
HREF="book1.html">
|
|
Packit |
98cdb6 |
REL="UP"
|
|
Packit |
98cdb6 |
TITLE="Writing Your Own Widgets"
|
|
Packit |
98cdb6 |
HREF="c2180.html">
|
|
Packit |
98cdb6 |
REL="PREVIOUS"
|
|
Packit |
98cdb6 |
TITLE="The Anatomy Of A Widget"
|
|
Packit |
98cdb6 |
HREF="x2189.html">
|
|
Packit |
98cdb6 |
REL="NEXT"
|
|
Packit |
98cdb6 |
TITLE="Creating a widget from scratch"
|
|
Packit |
98cdb6 |
HREF="x2310.html">
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
CLASS="SECT1"
|
|
Packit |
98cdb6 |
BGCOLOR="#FFFFFF"
|
|
Packit |
98cdb6 |
TEXT="#000000"
|
|
Packit |
98cdb6 |
LINK="#0000FF"
|
|
Packit |
98cdb6 |
VLINK="#840084"
|
|
Packit |
98cdb6 |
ALINK="#0000FF"
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
CLASS="NAVHEADER"
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
SUMMARY="Header navigation table"
|
|
Packit |
98cdb6 |
WIDTH="100%"
|
|
Packit |
98cdb6 |
BORDER="0"
|
|
Packit |
98cdb6 |
CELLPADDING="0"
|
|
Packit |
98cdb6 |
CELLSPACING="0"
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
COLSPAN="3"
|
|
Packit |
98cdb6 |
ALIGN="center"
|
|
Packit |
98cdb6 |
>GTK+ 2.0 Tutorial
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
WIDTH="10%"
|
|
Packit |
98cdb6 |
ALIGN="left"
|
|
Packit |
98cdb6 |
VALIGN="bottom"
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
HREF="x2189.html"
|
|
Packit |
98cdb6 |
ACCESSKEY="P"
|
|
Packit |
98cdb6 |
><<< Previous
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
WIDTH="80%"
|
|
Packit |
98cdb6 |
ALIGN="center"
|
|
Packit |
98cdb6 |
VALIGN="bottom"
|
|
Packit |
98cdb6 |
>Writing Your Own Widgets
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
WIDTH="10%"
|
|
Packit |
98cdb6 |
ALIGN="right"
|
|
Packit |
98cdb6 |
VALIGN="bottom"
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
HREF="x2310.html"
|
|
Packit |
98cdb6 |
ACCESSKEY="N"
|
|
Packit |
98cdb6 |
>Next >>>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
ALIGN="LEFT"
|
|
Packit |
98cdb6 |
WIDTH="100%">
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
CLASS="SECT1"
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
CLASS="SECT1"
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
NAME="SEC-CREATINGACOMPOSITEWIDGET"
|
|
Packit |
98cdb6 |
>Creating a Composite widget
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
CLASS="SECT2"
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
CLASS="SECT2"
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
NAME="AEN2202"
|
|
Packit |
98cdb6 |
>Introduction
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>One type of widget that you may be interested in creating is a
|
|
Packit |
98cdb6 |
widget that is merely an aggregate of other GTK widgets. This type of
|
|
Packit |
98cdb6 |
widget does nothing that couldn't be done without creating new
|
|
Packit |
98cdb6 |
widgets, but provides a convenient way of packaging user interface
|
|
Packit |
98cdb6 |
elements for reuse. The FileSelection and ColorSelection widgets in
|
|
Packit |
98cdb6 |
the standard distribution are examples of this type of widget.
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>The example widget that we'll create in this section is the Tictactoe
|
|
Packit |
98cdb6 |
widget, a 3x3 array of toggle buttons which triggers a signal when all
|
|
Packit |
98cdb6 |
three buttons in a row, column, or on one of the diagonals are
|
|
Packit |
98cdb6 |
depressed.
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
CLASS="EMPHASIS"
|
|
Packit |
98cdb6 |
>Note: the full source code for the Tictactoe example described
|
|
Packit |
98cdb6 |
below is in the
|
|
Packit |
98cdb6 |
HREF="a2901.html#SEC-TICTACTOE"
|
|
Packit |
98cdb6 |
>Code Examples Appendix
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
CLASS="INLINEMEDIAOBJECT"
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
SRC="images/tictactoe.png">
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
CLASS="SECT2"
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
CLASS="SECT2"
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
NAME="AEN2213"
|
|
Packit |
98cdb6 |
>Choosing a parent class
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>The parent class for a composite widget is typically the container
|
|
Packit |
98cdb6 |
class that holds all of the elements of the composite widget. For
|
|
Packit |
98cdb6 |
example, the parent class of the FileSelection widget is the
|
|
Packit |
98cdb6 |
Dialog class. Since our buttons will be arranged in a table, it
|
|
Packit |
98cdb6 |
is natural to make our parent class the Table class.
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
CLASS="SECT2"
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
CLASS="SECT2"
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
NAME="AEN2216"
|
|
Packit |
98cdb6 |
>The header file
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>Each GObject class has a header file which declares the object and
|
|
Packit |
98cdb6 |
class structures for that object, along with public functions.
|
|
Packit |
98cdb6 |
A couple of features are worth pointing out. To prevent duplicate
|
|
Packit |
98cdb6 |
definitions, we wrap the entire header file in:
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
BORDER="0"
|
|
Packit |
98cdb6 |
BGCOLOR="#E0E0E0"
|
|
Packit |
98cdb6 |
WIDTH="100%"
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
CLASS="PROGRAMLISTING"
|
|
Packit |
98cdb6 |
>#ifndef __TICTACTOE_H__
|
|
Packit |
98cdb6 |
#define __TICTACTOE_H__
|
|
Packit |
98cdb6 |
.
|
|
Packit |
98cdb6 |
.
|
|
Packit |
98cdb6 |
.
|
|
Packit |
98cdb6 |
#endif /* __TICTACTOE_H__ */
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>And to keep C++ programs that include the header file happy, in:
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
BORDER="0"
|
|
Packit |
98cdb6 |
BGCOLOR="#E0E0E0"
|
|
Packit |
98cdb6 |
WIDTH="100%"
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
CLASS="PROGRAMLISTING"
|
|
Packit |
98cdb6 |
>#include <glib.h>
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
G_BEGIN_DECLS
|
|
Packit |
98cdb6 |
.
|
|
Packit |
98cdb6 |
.
|
|
Packit |
98cdb6 |
.
|
|
Packit |
98cdb6 |
G_END_DECLS
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>Along with the functions and structures, we declare five standard
|
|
Packit |
98cdb6 |
macros in our header file,
|
|
Packit |
98cdb6 |
CLASS="LITERAL"
|
|
Packit |
98cdb6 |
>TICTACTOE_TYPE
|
|
Packit |
98cdb6 |
>,
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
CLASS="LITERAL"
|
|
Packit |
98cdb6 |
>TICTACTOE(obj)
|
|
Packit |
98cdb6 |
>,
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
CLASS="LITERAL"
|
|
Packit |
98cdb6 |
>TICTACTOE_CLASS(klass)
|
|
Packit |
98cdb6 |
>,
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
CLASS="LITERAL"
|
|
Packit |
98cdb6 |
>IS_TICTACTOE(obj)
|
|
Packit |
98cdb6 |
>, and
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
CLASS="LITERAL"
|
|
Packit |
98cdb6 |
>IS_TICTACTOE_CLASS(klass)
|
|
Packit |
98cdb6 |
>, which cast a
|
|
Packit |
98cdb6 |
pointer into a pointer to the object or class structure, and check
|
|
Packit |
98cdb6 |
if an object is a Tictactoe widget respectively.
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
CLASS="SECT2"
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
CLASS="SECT2"
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
NAME="AEN2228"
|
|
Packit |
98cdb6 |
>The
|
|
Packit |
98cdb6 |
CLASS="LITERAL"
|
|
Packit |
98cdb6 |
>_get_type()
|
|
Packit |
98cdb6 |
> function
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>We now continue on to the implementation of our widget. A core
|
|
Packit |
98cdb6 |
function for every object is the function
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
CLASS="LITERAL"
|
|
Packit |
98cdb6 |
>WIDGETNAME_get_type()
|
|
Packit |
98cdb6 |
>. This function, when first called, tells
|
|
Packit |
98cdb6 |
Glib about the new class, and gets an ID that uniquely identifies
|
|
Packit |
98cdb6 |
the class. Upon subsequent calls, it just returns the ID.
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
BORDER="0"
|
|
Packit |
98cdb6 |
BGCOLOR="#E0E0E0"
|
|
Packit |
98cdb6 |
WIDTH="100%"
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
CLASS="PROGRAMLISTING"
|
|
Packit |
98cdb6 |
>GType
|
|
Packit |
98cdb6 |
tictactoe_get_type (void)
|
|
Packit |
98cdb6 |
{
|
|
Packit |
98cdb6 |
static GType ttt_type = 0;
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
if (!ttt_type)
|
|
Packit |
98cdb6 |
{
|
|
Packit |
98cdb6 |
const GTypeInfo ttt_info =
|
|
Packit |
98cdb6 |
{
|
|
Packit |
98cdb6 |
sizeof (TictactoeClass),
|
|
Packit |
98cdb6 |
NULL, /* base_init */
|
|
Packit |
98cdb6 |
NULL, /* base_finalize */
|
|
Packit |
98cdb6 |
(GClassInitFunc) tictactoe_class_init,
|
|
Packit |
98cdb6 |
NULL, /* class_finalize */
|
|
Packit |
98cdb6 |
NULL, /* class_data */
|
|
Packit |
98cdb6 |
sizeof (Tictactoe),
|
|
Packit |
98cdb6 |
0, /* n_preallocs */
|
|
Packit |
98cdb6 |
(GInstanceInitFunc) tictactoe_init,
|
|
Packit |
98cdb6 |
};
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
ttt_type = g_type_register_static (GTK_TYPE_TABLE,
|
|
Packit |
98cdb6 |
"Tictactoe",
|
|
Packit |
98cdb6 |
&ttt_info,
|
|
Packit |
98cdb6 |
0);
|
|
Packit |
98cdb6 |
}
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
return ttt_type;
|
|
Packit |
98cdb6 |
}
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>The GTypeInfo structure has the following definition:
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
BORDER="0"
|
|
Packit |
98cdb6 |
BGCOLOR="#E0E0E0"
|
|
Packit |
98cdb6 |
WIDTH="100%"
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
CLASS="PROGRAMLISTING"
|
|
Packit |
98cdb6 |
>struct _GTypeInfo
|
|
Packit |
98cdb6 |
{
|
|
Packit |
98cdb6 |
/* interface types, classed types, instantiated types */
|
|
Packit |
98cdb6 |
guint16 class_size;
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
GBaseInitFunc base_init;
|
|
Packit |
98cdb6 |
GBaseFinalizeFunc base_finalize;
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
/* classed types, instantiated types */
|
|
Packit |
98cdb6 |
GClassInitFunc class_init;
|
|
Packit |
98cdb6 |
GClassFinalizeFunc class_finalize;
|
|
Packit |
98cdb6 |
gconstpointer class_data;
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
/* instantiated types */
|
|
Packit |
98cdb6 |
guint16 instance_size;
|
|
Packit |
98cdb6 |
guint16 n_preallocs;
|
|
Packit |
98cdb6 |
GInstanceInitFunc instance_init;
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
/* value handling */
|
|
Packit |
98cdb6 |
const GTypeValueTable *value_table;
|
|
Packit |
98cdb6 |
};
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>The important fields of this structure are pretty self-explanatory.
|
|
Packit |
98cdb6 |
We'll ignore the
|
|
Packit |
98cdb6 |
CLASS="LITERAL"
|
|
Packit |
98cdb6 |
>base_init
|
|
Packit |
98cdb6 |
> and
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
CLASS="LITERAL"
|
|
Packit |
98cdb6 |
>base_finalize
|
|
Packit |
98cdb6 |
> as well as the
|
|
Packit |
98cdb6 |
CLASS="LITERAL"
|
|
Packit |
98cdb6 |
>value_table
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
fields here. Once Glib has a correctly filled in copy of
|
|
Packit |
98cdb6 |
this structure, it knows how to create objects of a particular type.
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
CLASS="SECT2"
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
CLASS="SECT2"
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
NAME="AEN2240"
|
|
Packit |
98cdb6 |
>The
|
|
Packit |
98cdb6 |
CLASS="LITERAL"
|
|
Packit |
98cdb6 |
>_class_init()
|
|
Packit |
98cdb6 |
> function
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>The
|
|
Packit |
98cdb6 |
CLASS="LITERAL"
|
|
Packit |
98cdb6 |
>WIDGETNAME_class_init()
|
|
Packit |
98cdb6 |
> function initializes the fields of
|
|
Packit |
98cdb6 |
the widget's class structure, and sets up any signals for the
|
|
Packit |
98cdb6 |
class. For our Tictactoe widget it looks like:
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
BORDER="0"
|
|
Packit |
98cdb6 |
BGCOLOR="#E0E0E0"
|
|
Packit |
98cdb6 |
WIDTH="100%"
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
CLASS="PROGRAMLISTING"
|
|
Packit |
98cdb6 |
>enum {
|
|
Packit |
98cdb6 |
TICTACTOE_SIGNAL,
|
|
Packit |
98cdb6 |
LAST_SIGNAL
|
|
Packit |
98cdb6 |
};
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
static guint tictactoe_signals[LAST_SIGNAL] = { 0 };
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
static void
|
|
Packit |
98cdb6 |
tictactoe_class_init (TictactoeClass *klass)
|
|
Packit |
98cdb6 |
{
|
|
Packit |
98cdb6 |
tictactoe_signals[TICTACTOE_SIGNAL] =
|
|
Packit |
98cdb6 |
g_signal_new ("tictactoe",
|
|
Packit |
98cdb6 |
G_TYPE_FROM_CLASS (klass),
|
|
Packit |
98cdb6 |
G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
|
|
Packit |
98cdb6 |
G_STRUCT_OFFSET (TictactoeClass, tictactoe),
|
|
Packit |
98cdb6 |
NULL, NULL,
|
|
Packit |
98cdb6 |
g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
|
|
Packit |
98cdb6 |
}
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>Our widget has just one signal, the
|
|
Packit |
98cdb6 |
CLASS="LITERAL"
|
|
Packit |
98cdb6 |
>tictactoe
|
|
Packit |
98cdb6 |
> signal that is
|
|
Packit |
98cdb6 |
invoked when a row, column, or diagonal is completely filled in. Not
|
|
Packit |
98cdb6 |
every composite widget needs signals, so if you are reading this for
|
|
Packit |
98cdb6 |
the first time, you may want to skip to the next section now, as
|
|
Packit |
98cdb6 |
things are going to get a bit complicated.
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>The function:
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
BORDER="0"
|
|
Packit |
98cdb6 |
BGCOLOR="#E0E0E0"
|
|
Packit |
98cdb6 |
WIDTH="100%"
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
CLASS="PROGRAMLISTING"
|
|
Packit |
98cdb6 |
>guint g_signal_new( const gchar *signal_name,
|
|
Packit |
98cdb6 |
GType itype,
|
|
Packit |
98cdb6 |
GSignalFlags signal_flags,
|
|
Packit |
98cdb6 |
guint class_offset,
|
|
Packit |
98cdb6 |
GSignalAccumulator *accumulator,
|
|
Packit |
98cdb6 |
gpointer accu_data,
|
|
Packit |
98cdb6 |
GSignalCMarshaller *c_marshaller,
|
|
Packit |
98cdb6 |
GType return_type,
|
|
Packit |
98cdb6 |
guint n_params,
|
|
Packit |
98cdb6 |
...);
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>Creates a new signal. The parameters are:
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
CLASS="LITERAL"
|
|
Packit |
98cdb6 |
>signal_name
|
|
Packit |
98cdb6 |
>: The name of the signal.
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
CLASS="LITERAL"
|
|
Packit |
98cdb6 |
>itype
|
|
Packit |
98cdb6 |
>: The ID of the object that this signal applies
|
|
Packit |
98cdb6 |
to. (It will also apply to that objects descendants.)
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
CLASS="LITERAL"
|
|
Packit |
98cdb6 |
>signal_flags
|
|
Packit |
98cdb6 |
>: Whether the default handler runs before or after
|
|
Packit |
98cdb6 |
user handlers and other flags. Usually this will be one of
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
CLASS="LITERAL"
|
|
Packit |
98cdb6 |
>G_SIGNAL_RUN_FIRST
|
|
Packit |
98cdb6 |
> or
|
|
Packit |
98cdb6 |
CLASS="LITERAL"
|
|
Packit |
98cdb6 |
>G_SIGNAL_RUN_LAST
|
|
Packit |
98cdb6 |
>,
|
|
Packit |
98cdb6 |
although there are other possibilities. The flag
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
CLASS="LITERAL"
|
|
Packit |
98cdb6 |
>G_SIGNAL_ACTION
|
|
Packit |
98cdb6 |
> specifies that no extra code needs to
|
|
Packit |
98cdb6 |
run that performs special pre or post emission adjustments. This means that
|
|
Packit |
98cdb6 |
the signal can also be emitted from object external code.
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
CLASS="LITERAL"
|
|
Packit |
98cdb6 |
>class_offset
|
|
Packit |
98cdb6 |
>: The offset within the class structure of
|
|
Packit |
98cdb6 |
a pointer to the default handler.
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
CLASS="LITERAL"
|
|
Packit |
98cdb6 |
>accumulator
|
|
Packit |
98cdb6 |
>: For most classes this can
|
|
Packit |
98cdb6 |
be set to NULL.
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
CLASS="LITERAL"
|
|
Packit |
98cdb6 |
>accu_data
|
|
Packit |
98cdb6 |
>: User data that will be handed
|
|
Packit |
98cdb6 |
to the accumulator function.
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
CLASS="LITERAL"
|
|
Packit |
98cdb6 |
>c_marshaller
|
|
Packit |
98cdb6 |
>: A function that is used to invoke the signal
|
|
Packit |
98cdb6 |
handler. For signal handlers that have no arguments other than the
|
|
Packit |
98cdb6 |
object that emitted the signal and user data, we can use the
|
|
Packit |
98cdb6 |
pre-supplied marshaller function
|
|
Packit |
98cdb6 |
CLASS="LITERAL"
|
|
Packit |
98cdb6 |
>g_cclosure_marshal_VOID__VOID
|
|
Packit |
98cdb6 |
>.
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
CLASS="LITERAL"
|
|
Packit |
98cdb6 |
>return_type
|
|
Packit |
98cdb6 |
>: The type of the return value.
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
CLASS="LITERAL"
|
|
Packit |
98cdb6 |
>n_params
|
|
Packit |
98cdb6 |
>: The number of parameters of the signal handler
|
|
Packit |
98cdb6 |
(other than the two default ones mentioned above)
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
CLASS="LITERAL"
|
|
Packit |
98cdb6 |
>...
|
|
Packit |
98cdb6 |
>: The types of the parameters.
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>When specifying types, the following standard types can be used:
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
BORDER="0"
|
|
Packit |
98cdb6 |
BGCOLOR="#E0E0E0"
|
|
Packit |
98cdb6 |
WIDTH="100%"
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
CLASS="PROGRAMLISTING"
|
|
Packit |
98cdb6 |
>G_TYPE_INVALID
|
|
Packit |
98cdb6 |
G_TYPE_NONE
|
|
Packit |
98cdb6 |
G_TYPE_INTERFACE
|
|
Packit |
98cdb6 |
G_TYPE_CHAR
|
|
Packit |
98cdb6 |
G_TYPE_UCHAR
|
|
Packit |
98cdb6 |
G_TYPE_BOOLEAN
|
|
Packit |
98cdb6 |
G_TYPE_INT
|
|
Packit |
98cdb6 |
G_TYPE_UINT
|
|
Packit |
98cdb6 |
G_TYPE_LONG
|
|
Packit |
98cdb6 |
G_TYPE_ULONG
|
|
Packit |
98cdb6 |
G_TYPE_INT64
|
|
Packit |
98cdb6 |
G_TYPE_UINT64
|
|
Packit |
98cdb6 |
G_TYPE_ENUM
|
|
Packit |
98cdb6 |
G_TYPE_FLAGS
|
|
Packit |
98cdb6 |
G_TYPE_FLOAT
|
|
Packit |
98cdb6 |
G_TYPE_DOUBLE
|
|
Packit |
98cdb6 |
G_TYPE_STRING
|
|
Packit |
98cdb6 |
G_TYPE_POINTER
|
|
Packit |
98cdb6 |
G_TYPE_BOXED
|
|
Packit |
98cdb6 |
G_TYPE_PARAM
|
|
Packit |
98cdb6 |
G_TYPE_OBJECT
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
CLASS="LITERAL"
|
|
Packit |
98cdb6 |
>g_signal_new()
|
|
Packit |
98cdb6 |
> returns a unique integer identifier for the
|
|
Packit |
98cdb6 |
signal, that we store in the
|
|
Packit |
98cdb6 |
CLASS="LITERAL"
|
|
Packit |
98cdb6 |
>tictactoe_signals
|
|
Packit |
98cdb6 |
> array, which we
|
|
Packit |
98cdb6 |
index using an enumeration. (Conventionally, the enumeration elements
|
|
Packit |
98cdb6 |
are the signal name, uppercased, but here there would be a conflict
|
|
Packit |
98cdb6 |
with the
|
|
Packit |
98cdb6 |
CLASS="LITERAL"
|
|
Packit |
98cdb6 |
>TICTACTOE()
|
|
Packit |
98cdb6 |
> macro, so we called it
|
|
Packit |
98cdb6 |
CLASS="LITERAL"
|
|
Packit |
98cdb6 |
>TICTACTOE_SIGNAL
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
instead.
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
CLASS="SECT2"
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
CLASS="SECT2"
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
NAME="AEN2293"
|
|
Packit |
98cdb6 |
>The
|
|
Packit |
98cdb6 |
CLASS="LITERAL"
|
|
Packit |
98cdb6 |
>_init()
|
|
Packit |
98cdb6 |
> function
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>Each class also needs a function to initialize the object
|
|
Packit |
98cdb6 |
structure. Usually, this function has the fairly limited role of
|
|
Packit |
98cdb6 |
setting the fields of the structure to default values. For composite
|
|
Packit |
98cdb6 |
widgets, however, this function also creates the component widgets.
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
BORDER="0"
|
|
Packit |
98cdb6 |
BGCOLOR="#E0E0E0"
|
|
Packit |
98cdb6 |
WIDTH="100%"
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
CLASS="PROGRAMLISTING"
|
|
Packit |
98cdb6 |
>static void
|
|
Packit |
98cdb6 |
tictactoe_init (Tictactoe *ttt)
|
|
Packit |
98cdb6 |
{
|
|
Packit |
98cdb6 |
gint i,j;
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
gtk_table_resize (GTK_TABLE (ttt), 3, 3);
|
|
Packit |
98cdb6 |
gtk_table_set_homogeneous (GTK_TABLE (ttt), TRUE);
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
for (i=0;i<3; i++)
|
|
Packit |
98cdb6 |
for (j=0;j<3; j++)
|
|
Packit |
98cdb6 |
{
|
|
Packit |
98cdb6 |
ttt->buttons[i][j] = gtk_toggle_button_new ();
|
|
Packit |
98cdb6 |
gtk_table_attach_defaults (GTK_TABLE (ttt), ttt->buttons[i][j],
|
|
Packit |
98cdb6 |
i, i+1, j, j+1);
|
|
Packit |
98cdb6 |
g_signal_connect (ttt->buttons[i][j], "toggled",
|
|
Packit |
98cdb6 |
G_CALLBACK (tictactoe_toggle), ttt);
|
|
Packit |
98cdb6 |
gtk_widget_set_size_request (ttt->buttons[i][j], 20, 20);
|
|
Packit |
98cdb6 |
gtk_widget_show (ttt->buttons[i][j]);
|
|
Packit |
98cdb6 |
}
|
|
Packit |
98cdb6 |
}
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
CLASS="SECT2"
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
CLASS="SECT2"
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
NAME="AEN2298"
|
|
Packit |
98cdb6 |
>And the rest...
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>There is one more function that every object (except for abstract
|
|
Packit |
98cdb6 |
classes like Bin that cannot be instantiated) needs to have - the
|
|
Packit |
98cdb6 |
function that the user calls to create an object of that type. This is
|
|
Packit |
98cdb6 |
conventionally called
|
|
Packit |
98cdb6 |
CLASS="LITERAL"
|
|
Packit |
98cdb6 |
>OBJECTNAME_new()
|
|
Packit |
98cdb6 |
>. In some
|
|
Packit |
98cdb6 |
widgets, though not for the Tictactoe widgets, this function takes
|
|
Packit |
98cdb6 |
arguments, and does some setup based on the arguments. The other two
|
|
Packit |
98cdb6 |
functions are specific to the Tictactoe widget.
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
CLASS="LITERAL"
|
|
Packit |
98cdb6 |
>tictactoe_clear()
|
|
Packit |
98cdb6 |
> is a public function that resets all the
|
|
Packit |
98cdb6 |
buttons in the widget to the up position. Note the use of
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
CLASS="LITERAL"
|
|
Packit |
98cdb6 |
>g_signal_handlers_block_matched()
|
|
Packit |
98cdb6 |
> to keep our signal handler for
|
|
Packit |
98cdb6 |
button toggles from being triggered unnecessarily.
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
CLASS="LITERAL"
|
|
Packit |
98cdb6 |
>tictactoe_toggle()
|
|
Packit |
98cdb6 |
> is the signal handler that is invoked when the
|
|
Packit |
98cdb6 |
user clicks on a button. It checks to see if there are any winning
|
|
Packit |
98cdb6 |
combinations that involve the toggled button, and if so, emits
|
|
Packit |
98cdb6 |
the "tictactoe" signal.
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
BORDER="0"
|
|
Packit |
98cdb6 |
BGCOLOR="#E0E0E0"
|
|
Packit |
98cdb6 |
WIDTH="100%"
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
CLASS="PROGRAMLISTING"
|
|
Packit |
98cdb6 |
>GtkWidget*
|
|
Packit |
98cdb6 |
tictactoe_new (void)
|
|
Packit |
98cdb6 |
{
|
|
Packit |
98cdb6 |
return GTK_WIDGET ( g_object_new (TICTACTOE_TYPE, NULL));
|
|
Packit |
98cdb6 |
}
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
void
|
|
Packit |
98cdb6 |
tictactoe_clear (Tictactoe *ttt)
|
|
Packit |
98cdb6 |
{
|
|
Packit |
98cdb6 |
int i,j;
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
for (i=0;i<3;i++)
|
|
Packit |
98cdb6 |
for (j=0;j<3;j++)
|
|
Packit |
98cdb6 |
{
|
|
Packit |
98cdb6 |
g_signal_handlers_block_matched (G_OBJECT (ttt->buttons[i][j]),
|
|
Packit |
98cdb6 |
G_SIGNAL_MATCH_DATA,
|
|
Packit |
98cdb6 |
0, 0, NULL, NULL, ttt);
|
|
Packit |
98cdb6 |
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ttt->buttons[i][j]),
|
|
Packit |
98cdb6 |
FALSE);
|
|
Packit |
98cdb6 |
g_signal_handlers_unblock_matched (G_OBJECT (ttt->buttons[i][j]),
|
|
Packit |
98cdb6 |
G_SIGNAL_MATCH_DATA,
|
|
Packit |
98cdb6 |
0, 0, NULL, NULL, ttt);
|
|
Packit |
98cdb6 |
}
|
|
Packit |
98cdb6 |
}
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
static void
|
|
Packit |
98cdb6 |
tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt)
|
|
Packit |
98cdb6 |
{
|
|
Packit |
98cdb6 |
int i,k;
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
static int rwins[8][3] = { { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
|
|
Packit |
98cdb6 |
{ 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
|
|
Packit |
98cdb6 |
{ 0, 1, 2 }, { 0, 1, 2 } };
|
|
Packit |
98cdb6 |
static int cwins[8][3] = { { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
|
|
Packit |
98cdb6 |
{ 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
|
|
Packit |
98cdb6 |
{ 0, 1, 2 }, { 2, 1, 0 } };
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
int success, found;
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
for (k=0; k<8; k++)
|
|
Packit |
98cdb6 |
{
|
|
Packit |
98cdb6 |
success = TRUE;
|
|
Packit |
98cdb6 |
found = FALSE;
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
for (i=0;i<3;i++)
|
|
Packit |
98cdb6 |
{
|
|
Packit |
98cdb6 |
success = success &&
|
|
Packit |
98cdb6 |
GTK_TOGGLE_BUTTON(ttt->buttons[rwins[k][i]][cwins[k][i]])->active;
|
|
Packit |
98cdb6 |
found = found ||
|
|
Packit |
98cdb6 |
ttt->buttons[rwins[k][i]][cwins[k][i]] == widget;
|
|
Packit |
98cdb6 |
}
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
if (success && found)
|
|
Packit |
98cdb6 |
{
|
|
Packit |
98cdb6 |
g_signal_emit (ttt,
|
|
Packit |
98cdb6 |
tictactoe_signals[TICTACTOE_SIGNAL], 0);
|
|
Packit |
98cdb6 |
break;
|
|
Packit |
98cdb6 |
}
|
|
Packit |
98cdb6 |
}
|
|
Packit |
98cdb6 |
}
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>And finally, an example program using our Tictactoe widget:
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
BORDER="0"
|
|
Packit |
98cdb6 |
BGCOLOR="#E0E0E0"
|
|
Packit |
98cdb6 |
WIDTH="100%"
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
CLASS="PROGRAMLISTING"
|
|
Packit |
98cdb6 |
>#include <gtk/gtk.h>
|
|
Packit |
98cdb6 |
#include "tictactoe.h"
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
/* Invoked when a row, column or diagonal is completed */
|
|
Packit |
98cdb6 |
void
|
|
Packit |
98cdb6 |
win (GtkWidget *widget, gpointer data)
|
|
Packit |
98cdb6 |
{
|
|
Packit |
98cdb6 |
g_print ("Yay!\n");
|
|
Packit |
98cdb6 |
tictactoe_clear (TICTACTOE (widget));
|
|
Packit |
98cdb6 |
}
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
int
|
|
Packit |
98cdb6 |
main (int argc, char *argv[])
|
|
Packit |
98cdb6 |
{
|
|
Packit |
98cdb6 |
GtkWidget *window;
|
|
Packit |
98cdb6 |
GtkWidget *ttt;
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
gtk_init (&argc, &argv);
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
g_signal_connect (window, "destroy",
|
|
Packit |
98cdb6 |
G_CALLBACK (exit), NULL);
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
gtk_container_set_border_width (GTK_CONTAINER (window), 10);
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
/* Create a new Tictactoe widget */
|
|
Packit |
98cdb6 |
ttt = tictactoe_new ();
|
|
Packit |
98cdb6 |
gtk_container_add (GTK_CONTAINER (window), ttt);
|
|
Packit |
98cdb6 |
gtk_widget_show (ttt);
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
/* And attach to its "tictactoe" signal */
|
|
Packit |
98cdb6 |
g_signal_connect (ttt, "tictactoe",
|
|
Packit |
98cdb6 |
G_CALLBACK (win), NULL);
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
gtk_widget_show (window);
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
gtk_main ();
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
return 0;
|
|
Packit |
98cdb6 |
}
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
CLASS="NAVFOOTER"
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
ALIGN="LEFT"
|
|
Packit |
98cdb6 |
WIDTH="100%">
|
|
Packit |
98cdb6 |
SUMMARY="Footer navigation table"
|
|
Packit |
98cdb6 |
WIDTH="100%"
|
|
Packit |
98cdb6 |
BORDER="0"
|
|
Packit |
98cdb6 |
CELLPADDING="0"
|
|
Packit |
98cdb6 |
CELLSPACING="0"
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
WIDTH="33%"
|
|
Packit |
98cdb6 |
ALIGN="left"
|
|
Packit |
98cdb6 |
VALIGN="top"
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
HREF="x2189.html"
|
|
Packit |
98cdb6 |
ACCESSKEY="P"
|
|
Packit |
98cdb6 |
><<< Previous
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
WIDTH="34%"
|
|
Packit |
98cdb6 |
ALIGN="center"
|
|
Packit |
98cdb6 |
VALIGN="top"
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
HREF="book1.html"
|
|
Packit |
98cdb6 |
ACCESSKEY="H"
|
|
Packit |
98cdb6 |
>Home
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
WIDTH="33%"
|
|
Packit |
98cdb6 |
ALIGN="right"
|
|
Packit |
98cdb6 |
VALIGN="top"
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
HREF="x2310.html"
|
|
Packit |
98cdb6 |
ACCESSKEY="N"
|
|
Packit |
98cdb6 |
>Next >>>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
WIDTH="33%"
|
|
Packit |
98cdb6 |
ALIGN="left"
|
|
Packit |
98cdb6 |
VALIGN="top"
|
|
Packit |
98cdb6 |
>The Anatomy Of A Widget
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
WIDTH="34%"
|
|
Packit |
98cdb6 |
ALIGN="center"
|
|
Packit |
98cdb6 |
VALIGN="top"
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
HREF="c2180.html"
|
|
Packit |
98cdb6 |
ACCESSKEY="U"
|
|
Packit |
98cdb6 |
>Up
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
WIDTH="33%"
|
|
Packit |
98cdb6 |
ALIGN="right"
|
|
Packit |
98cdb6 |
VALIGN="top"
|
|
Packit |
98cdb6 |
>Creating a widget from scratch
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|
|
Packit |
98cdb6 |
>
|