791 lines
32 KiB
HTML
791 lines
32 KiB
HTML
<!-- $Id: oop.tex.html,v 1.2 2000/11/11 23:34:47 idiscovery Exp $ -->
|
|
<H1><A NAME=6>6 Tix Object Oriented Programming</H1>
|
|
|
|
<p> <i> This chapter is intended for experienced programmers who want to
|
|
create new Tix widgets. If you just want use the Tix widgets in your
|
|
applications, you can skip this chapter.</i>
|
|
|
|
<p><H2><A NAME=6.1>6.1 Introduction to Tix Object Oriented Programming</H2>
|
|
|
|
<p> Tix comes with a simple object oriented programming (OOP) framework,
|
|
the <i> Tix Intrinsics</i>, for writing mega-widgets. The Tix
|
|
Intrinsics is not a general purpose OOP system and it does not
|
|
support some features found in general purpose OOP systems such as
|
|
<code> [incr Tcl]</code>. However, the Tix Intrinsics is specially designed
|
|
for writing mega-widgets. It provides a simple and efficient
|
|
interface for creating mega-widgets so that you can avoid the
|
|
complexity and overheads of the general purpose OOP extensions to
|
|
Tcl.
|
|
|
|
<p> The hard thing about programming with mega-widgets is to make sure
|
|
that each instance you create can handle its own activities. Events
|
|
must be directed to the right widget, procedures must act on data
|
|
that is internal to that widget, and users should be able to change
|
|
the options associated with the widget. For instance, we'll show an
|
|
arrow widget that needs to know what direction it's pointing; this
|
|
requires each instance of the widget to have its own variable.
|
|
|
|
<p> Furthermore, each widget should respond properly to changes
|
|
requested by the application programmer during the program's run.
|
|
The whole reason people use Tcl/Tk is because they can alter things
|
|
on the fly.
|
|
|
|
<p> The advantage of an object-oriented programming system is that you
|
|
can easily associate a widget with its own data and procedures
|
|
(methods). This chapter shows how to do that, and how to configure
|
|
data both at the time the widget is initialized and later during the
|
|
program.
|
|
|
|
<p>
|
|
<H3><A NAME=6.1.1>6.1.1 Widget Classes and Widget Instances</H3>
|
|
|
|
<p> All the mega-widget classes in Tix, such as TixComboBox and
|
|
TixControl, are implemented in the Tix Intrinsics framework. Also,
|
|
you can write new <i> widget classes</i> with the Tix Intrinsics. In
|
|
the next section, I'll go through all the steps of creating a new
|
|
widget class in Tix. I'll illustrate the idea using a new class
|
|
``TixArrowButton'' as an example. TixArrowButton is essentially a
|
|
button that can display an arrow in one of the for directions
|
|
(see figure <a href=oop.tex.html#6-1>6-1 </a>).
|
|
|
|
<p><blockquote><a name=6-1>
|
|
<center><img src=fig/oop/arrows.gif></center>
|
|
<hr><center><h3>(Figure 6-1) Arrow Buttons</center></h3>
|
|
</blockquote>
|
|
|
|
<p> Once you have defined your classes, you can create <i> widget
|
|
instances</i> of these classes. For example, the following code will
|
|
create four instances of your new TixArrowButton class:
|
|
|
|
<p><blockquote><pre>
|
|
tixArrowButton .up -direction n
|
|
tixArrowButton .left -direction e
|
|
tixArrowButton .right -direction w
|
|
tixArrowButton .down -direction s
|
|
</pre></blockquote>
|
|
|
|
<p><H3><A NAME=6.1.2>6.1.2 What is in a Widget Instance</H3>
|
|
|
|
<p> Each widget instance is composed of three integral parts: variables,
|
|
methods and component widgets
|
|
|
|
<p><H4><A NAME=6.1.2.1> Variables</H4>
|
|
|
|
<p> Each widget instance is associated with a set of variables. In the
|
|
example of an instance of the TixArrowButton class, we may use a
|
|
variable to store the direction to which the arrow is pointing
|
|
to. We may also use a variable to count how many times the user has
|
|
pressed the button.
|
|
|
|
<p> Each variable can be public or private. Public variables may be
|
|
accessed by the application programmer (usually via <code> configure</code>
|
|
or cget <code> methods</code>) and their names usually start with a dash
|
|
(<code> -</code>). They usually are used to represent some user-configurable
|
|
options of the widget instance. Private variables, on the other
|
|
hand, cannot be accessed by the application programmer. They are
|
|
usually used to store information about the widget instance that are
|
|
of interests only to the widget writer.
|
|
|
|
<p> All the variables of an instance are stored in a global array that
|
|
has the same name as the instance. For example, the variables of the
|
|
instance <code> .up</code> are stored in the global array <code> .up:</code>. The
|
|
public variable <code> -direction</code>, which records the direction to
|
|
which the arrow is pointing to, is stored in <code> .up(-direction)</code>.
|
|
The private variable <code> count</code>, which counts how many times the
|
|
user has pressed the button, is stored in <code> .up(count)</code>. In
|
|
comparison, the same variables of the <code> .down</code> instance are
|
|
stored in <code> .down(-direction)</code> and <code> .down(count)</code>.
|
|
|
|
<p><H4><A NAME=6.1.2.2> Methods</H4>
|
|
|
|
<p> To carry out operations on the widget, you define a set of
|
|
procedures called <i> methods</i> (to use common object-oriented
|
|
terminology). Each method can be declared as public or private. <i>
|
|
Public methods</i> can be called by the application programmer. For
|
|
example, if the TixArrowButton class supports the public methods
|
|
<code> invoke</code> and <code> invert</code>, the application programmer can issue
|
|
the commands to call these method for the widget instance <code> .up</code>.
|
|
|
|
<p><blockquote><pre>
|
|
.up invert
|
|
.up invoke
|
|
</pre></blockquote>
|
|
In contrast, <i> Private methods</i> are of interests only to widget
|
|
writers and cannot be called by application programmers.
|
|
|
|
<p><H4><A NAME=6.1.2.3> Component Widgets</H4>
|
|
|
|
<p> A Tix mega-widget is composed of one or more component
|
|
widgets. The main part of a mega-widget is called the <i> root
|
|
widget</i>, which is usually a frame widget that encompasses all other
|
|
component widgets. The other component widgets are called <i>
|
|
subwidgets</i>.
|
|
|
|
<p> The root widget has the same name as the the mega-widget itself. In
|
|
the above example, we have a mega-widget called <code> .up</code>. It has a
|
|
root widget which is a frame widget and is also called <code>
|
|
.up</code>. Inside <code> .up</code> we have a button subwidget called <code>
|
|
.up.button</code>.
|
|
|
|
<p> Similar to variables and methods, component widgets are also
|
|
classified into public and private component widgets. Only public
|
|
widgets may be accessed by the application programmer, via the <code>
|
|
subwidget</code> method (see section <a href=intro.tex.html#1.3.1>1.3.1 </a>) of each widget
|
|
instance.
|
|
|
|
<p><H2><A NAME=6.2>6.2 Widget Class Declaration</H2>
|
|
|
|
<p> The first step of writing a new widget class is to decide the base
|
|
class from which the new class. Usually, if the new class does not
|
|
share any common features with other classes, it should be derived
|
|
from the TixPrimitive class. If it does share common features with
|
|
other classes, then it should be derived from the appropriate base
|
|
class. For example, if the new class support scrollbars, it should
|
|
be derived from TixScrolledWidget; if it displays a label next to
|
|
its ``main area'', then it should be derived from TixLabelWidget.
|
|
|
|
<p> In the case of our new TixArrowButton class, it doesn't really share
|
|
any common features with other classes, so we decide to use the base
|
|
class TixPrimitive as its superclass.
|
|
|
|
<p>
|
|
<H3><A NAME=6.2.1>6.2.1 Using the tixWidgetClass Command</H3>
|
|
|
|
<p> We can use the <code> tixWidgetClass</code> command to declare a new
|
|
class. The syntax is:
|
|
|
|
<p><blockquote><pre>
|
|
tixWidgetClass classCommandName {
|
|
-switch value
|
|
-switch value
|
|
....
|
|
}
|
|
</pre></blockquote>
|
|
For example, the following is the declaration section of
|
|
TixArrowButton:
|
|
|
|
<p><blockquote><a name=6-2>
|
|
<pre>
|
|
tixWidgetClass tixArrowButton {
|
|
-classname TixArrowButton
|
|
-superclass tixPrimitive
|
|
-method {
|
|
flash invoke invert
|
|
}
|
|
-flag {
|
|
-direction -state
|
|
}
|
|
-configspec {
|
|
{-direction direction Direction e}
|
|
{-state state State normal}
|
|
}
|
|
-alias {
|
|
{-dir -direction}
|
|
}
|
|
-default {
|
|
{*Button.anchor c}
|
|
{*Button.padX 5}
|
|
}
|
|
}
|
|
</pre>
|
|
<hr><center><h3>(Figure 6-2) declaration of the TixArrowButton Class</center></h3>
|
|
</blockquote>
|
|
|
|
<p> We'll look at what each option means as I describe the command in
|
|
the following sections.
|
|
|
|
<p> The first argument for <code> tixWidgetClass</code> is the <i> command
|
|
name</i> for the widget class (<code> tixArrowButton</code>). Command names are
|
|
used to create widgets of this class. For example, the code
|
|
|
|
<p><blockquote><pre>
|
|
tixArrowButton .arrow
|
|
</pre></blockquote>
|
|
creates a widget instance <code> .arrow</code> of the class
|
|
TixArrowButton. Also, the command name is used as a prefix of all
|
|
the methods of this class. For example, the <code> Foo</code> and <code> Bar</code>
|
|
methods of the class TixArrowButton will be written as <code>
|
|
tixArrowButton:Foo</code> and <code> tixArrowButton:Bar</code>.
|
|
|
|
<p> The <i> class name</i> of the class (<code> TixArrowButton</code>)is specified
|
|
by the <code> -classname</code> switch inside the main body of the
|
|
declaration. The class name is used only to specify options in the
|
|
TK option database. For example, the following commands specifies
|
|
the TixArrowButton widget instances should have the default value
|
|
<code> up</code> for their <code> -direction</code> option and the default value
|
|
<code> normal</code> for their <code> -state</code> option.
|
|
|
|
<p><blockquote><pre>
|
|
option add *TixArrowButton.direction up
|
|
option add *TixArrowButton.state normal
|
|
</pre></blockquote>
|
|
|
|
<p> <!ignored:nind> Notice the difference in the capitalization of the class name
|
|
and the command name of the TixArrowButton class: both of them has
|
|
the individual words capitalized, but the command name (<code>
|
|
tixArrowButton</code>)starts with a lower case letter while the class name
|
|
(<code> TixArrowButton</code>) starts with an upper case letter. When you
|
|
create your own classes, you should follow this naming convention.
|
|
|
|
<p>
|
|
The <code> -superclass</code> switch specifies the superclass of the new
|
|
widget. In our example, we have set it to <code> tixPrimitive</code>. Again,
|
|
pay attention to the capitalization: we should use the command name
|
|
of the superclass, not its class name.
|
|
|
|
<p><H2><A NAME=6.3>6.3 Writing Methods</H2>
|
|
|
|
<p> After we have declared the new widget class, we can write methods
|
|
for this class to define its behavior. Methods are just a special
|
|
type of TCL procedures and they are created by the <code> proc</code>
|
|
command. There are, however, three requirements for methods. First,
|
|
their names must be prefixed by the command name of their
|
|
class. Second, they must accept at least one argument and the first
|
|
argument that they accept must be called <code> w</code>. Third, the first
|
|
command executed inside each method must be
|
|
|
|
<p><blockquote><pre>
|
|
upvar #0 $w data
|
|
</pre></blockquote>
|
|
|
|
<p> For example, the following is an implementation of the invert method
|
|
for the class TixArrowButton:
|
|
|
|
<p><blockquote><pre>
|
|
proc tixArrowButton:invert {w} {
|
|
upvar #0 $w data
|
|
|
|
<p> set curDirection $data(-direction)
|
|
case $curDirection {
|
|
n {
|
|
set newDirection s
|
|
}
|
|
s {
|
|
set newDirection n
|
|
}
|
|
# ....
|
|
}
|
|
}
|
|
</pre></blockquote>
|
|
Notice that the name of the method is prefixed by the command name
|
|
of the class (<code> tixArrowButton</code>). Also, the first and only
|
|
argument that it accepts is <code> w</code> and the first line it executes
|
|
is ``<code> upvar #0 $w data</code>''.
|
|
|
|
<p> The argument <code> w</code> specifies which widget instance this method
|
|
should act upon. For example, if the user has issued the command
|
|
|
|
<p><blockquote><pre>
|
|
.up invert
|
|
</pre></blockquote>
|
|
on an instance <code> .up</code> of the class tixArrowButton, the method
|
|
<code> tixArrowButton:invert</code> will be called and the argument <code> w</code>
|
|
will have the value <code> .up</code>.
|
|
|
|
<p> The <code> invert</code> method is used to invert the direction of the
|
|
arrow. Therefore, it should examine the variable <code>
|
|
.up(-direction)</code>, which stores the current direction of the instance
|
|
<code> .up</code>, and modify it appropriately. It turns out that in TCL,
|
|
the only clean way to access an array whose name is stored in a
|
|
variable is the ``<code> upvar #0 $w data</code>'' technique: essentially
|
|
it tells the intepreter that the array data should be an alias for
|
|
the global array whose name is stored in <code> $w</code>. We will soon see
|
|
how the widget's methods use the data array.
|
|
|
|
<p> Once the mysterious ``<code> upvar #0 $w data</code>'' line is explained,
|
|
it becomes clear what the rest of the <code> tixArrowButton:invert</code>
|
|
method does: it examines the current direction of the arrow, which
|
|
is stored in <code> $data(-direction)</code> and inverts it.
|
|
|
|
<p><H3><A NAME=6.3.1>6.3.1 Declaring Public Methods</H3>
|
|
|
|
<p> All the methods of a class are by default private methods and cannot
|
|
be accessed by the application programmer. If you want to make a
|
|
method public, you can include its name in the <code> -method</code> section
|
|
of the class declaration. In our TixArrowButton example, we have
|
|
declared that the methods <code> flash</code>, <code> invert</code> and <code> invoke</code>
|
|
are public methods and they can be accessed by the application
|
|
programmer. All other methods of the TixArrowButton class will be
|
|
private.
|
|
|
|
<p> Usually, the names of private methods start with a capital letter
|
|
with individual words capitalized. The names of public methods
|
|
start with a lowercase letter.
|
|
|
|
<p><H2><A NAME=6.4>6.4 Standard Initialization Methods</H2>
|
|
|
|
<p> Each new mega-widget class must supply three standard initialization
|
|
methods. When an instance of a Tix widget is created, three
|
|
three methods will be called to initialize this instance. The
|
|
methods are <code> InitWidgetRec</code>, <code> ConstructWidget</code> and <code>
|
|
SetBindings</code> and they will be called in that order. The following
|
|
sections show how these methods can be implemented.
|
|
|
|
<p><H3><A NAME=6.4.1>6.4.1 The InitWidgetRec Method</H3>
|
|
|
|
<p> The purpose of the <code> InitWidgetRec</code> method is to initialize the
|
|
variables of the widget instance. For example, the following
|
|
implementation of <code> tixArrowButton:InitWidgetRec</code> sets the <code>
|
|
count</code> variable of each newly created instance to zero.
|
|
|
|
<p><blockquote><pre>
|
|
proc tixArrowButton:InitWidgetRec {w} {
|
|
upvar #0 $w data
|
|
|
|
<p> set data(count) 0
|
|
}
|
|
</pre></blockquote>
|
|
|
|
<p> Earlier, we showed how each widget you create is associated with an
|
|
array of the same name. Within the methods, you always refer to
|
|
this array through the name <code> data</code> --the method then works
|
|
properly in each instance of the widget.
|
|
|
|
<p><H4><A NAME=6.4.1.1> Chaining Methods</H4>
|
|
|
|
<p> The above implementation is not sufficient because our
|
|
TixArrowButton class is derived from TixPrimitive. The class
|
|
derivation in Tix is basically an <i> is-a</i> relationship:
|
|
TixArrowButton <i> is a</i> TixPrimitive. TixPrimitive defines the
|
|
method <code> tixPrimitive:InitWidgetRec</code> which sets up the instance
|
|
variables of every instance of TixPrimitive. Since an instance of
|
|
TixArrowButton is also an instance of TixPrimitive, we need to make
|
|
sure that the instance variables defined by TixPrimitive are also
|
|
properly initialized. The technique of calling a method defined in a
|
|
superclass is called the <i> chaining</i> of a method. The following
|
|
implementation does this correctly:
|
|
|
|
<p>
|
|
<blockquote><pre>
|
|
proc tixArrowButton:InitWidgetRec {w} {
|
|
upvar #0 $w data
|
|
|
|
<p> tixPrimitive:InitWidgetRec $w
|
|
set data(count) 0
|
|
}
|
|
</pre></blockquote>
|
|
Notice that <code> tixPrimitive:InitWidgetRec</code> is called before anything
|
|
else is done. This way, we can define new classes by means of
|
|
successive refinement: we can first ask the superclass to set up the
|
|
instance variables, then we can modify some of those variables when
|
|
necessary and also define new variables.
|
|
|
|
<p><H4><A NAME=6.4.1.2> The tixChainMethod call</H4>
|
|
|
|
<p> The above implementation of <code> tixArrowButton:InitWidgetRec</code> is
|
|
correct but it may be cumbersome if we want to switch
|
|
superclasses. For example, suppose we want to create a new base class
|
|
TixArrowWidget, which presumably defines common attributes of any
|
|
class that have arrows in them. Then, instead of deriving
|
|
TixArrowButton directly from TixPrimitive, we decide to derive
|
|
TixArrowButton from TixArrowWidget, which is in turn derived from
|
|
TixPrimitive:
|
|
|
|
<p><blockquote><pre>
|
|
tixWidgetClass tixArrowWidget {
|
|
-superclass tixPrimitive
|
|
...
|
|
}
|
|
tixWidgetClass tixArrowButton {
|
|
-superclass tixArrowWidget
|
|
...
|
|
}
|
|
</pre></blockquote>
|
|
Now we would need to change all the method chaining calls in
|
|
TixArrowButton from:
|
|
|
|
<p><blockquote><pre>
|
|
tixPrimitive:SomeMethod
|
|
</pre></blockquote>
|
|
to:
|
|
|
|
<p><blockquote><pre>
|
|
tixArrowWidget:SomeMethod
|
|
</pre></blockquote>
|
|
This may be a lot of work because you may have chained methods in many
|
|
places in the original implementation of TixArrowButton.
|
|
|
|
<p> The <code> tixChainMethod</code> command solves this problem. It will
|
|
automatically find a superclass that defines the method we want to
|
|
chain and calls this method for us. For example, the following is a
|
|
better implementation of <code> tixArrowButton:InitWidgetRec</code> that
|
|
uses <code> tixChainMethod</code> to avoid calling <code>
|
|
tixPrimitive:InitWidgetRec</code> directly:
|
|
|
|
<p><blockquote><pre>
|
|
proc tixArrowButton:InitWidgetRec {w} {
|
|
upvar #0 $w data
|
|
|
|
<p> tixChainMethod $w InitWidgetRec
|
|
set data(count) 0
|
|
}
|
|
</pre></blockquote>
|
|
Notice the order of the arguments for tixChainMethod: the name of
|
|
the instance, <code> $w</code>, is passed before the method we want to
|
|
chain, <code> InitWidgetRec</code>. In general, if the method we want to
|
|
chain has $1+n$ arguments:
|
|
|
|
<p><blockquote><pre>
|
|
proc tixPrimitive:MethodToChain {w arg1 arg2 ... argn} {
|
|
...
|
|
}
|
|
</pre></blockquote>
|
|
We call it with the arguments in the following order
|
|
|
|
<p><blockquote><pre>
|
|
tixChainMethod $w MethodToChain $arg1 $arg2 ... $argn
|
|
</pre></blockquote>
|
|
We'll come back to more detailed discussion of <code> tixChainMethod</code>
|
|
shortly. For the time being, let's take it for granted that <code>
|
|
tixChainMethod</code> must be used in the three standard initialization
|
|
methods: <code> InitWidgetRec</code>, <code> ConstructWidget</code> and <code>
|
|
SetBindings</code>
|
|
|
|
<p><H3><A NAME=6.4.2>6.4.2 The ConstructWidget Method</H3>
|
|
|
|
<p> The <code> ConstructWidget</code> method is used to creates the components
|
|
of a widget instance. In the case of TixArrowButton, we want to
|
|
create a new button subwidget, whose name is <code> button</code>, and use a
|
|
bitmap to display an arrow on this button. Assuming the bitmap files
|
|
are stored in the files <code> up.xbm</code>, <code> down.xbm</code>, <code> left.xbm</code>
|
|
and <code> right.xbm</code>, the string substitution <code>
|
|
@$data(-direction).xbm</code> will give us the appropriate bitmap
|
|
depending on the current direction option of the widget instance.
|
|
|
|
<p><blockquote><pre>
|
|
proc tixArrowButton:ConstructWidget {w} {
|
|
upvar #0 $w data
|
|
|
|
<p> tixChainMethod $w ConstructWidget
|
|
|
|
<p> set data(w:button) [button $w.button -bitmap @$data(-direction).xbm]
|
|
pack $data(w:button) -expand yes -fill both
|
|
}
|
|
</pre></blockquote>
|
|
|
|
<p> The <code> tixArrowButton:ConstructWidget</code> method shown above sets
|
|
the variable <code> data(w:button)</code> to be the pathname of the <code>
|
|
button</code> subwidget. As a convention of the Tix Intrinsics, we must
|
|
declare a public subwidget <i> swid</i> by storing its pathname in the
|
|
variable <code> data(w:</code><i> swid</i><code> )</code>.
|
|
|
|
<p><H3><A NAME=6.4.3>6.4.3 The SetBindings Method</H3>
|
|
|
|
<p> In your interface, you want to handle a lot of events in the
|
|
subwidgets that make up your mega-widget. For instance, when
|
|
somebody presses the button in a TixArrowButton widget, you want the
|
|
button to handle the event. The <code> SetBindings</code> method is used to
|
|
creates event bindings for the components inside the mega-widget. In
|
|
our TixArrowButton example, we use the bind command to specify that
|
|
the method <code> tixArrowButton:IncrCount</code> should be called each
|
|
time when the user presses the first mouse button. As a result, we
|
|
can count the number of times the user has pressed on the button
|
|
(obviously for no better reasons than using it as a dumb example).
|
|
|
|
<p><blockquote><pre>
|
|
proc tixArrowButton:SetBindings {w} {
|
|
upvar #0 $w data
|
|
|
|
<p> tixChainMethod $w SetBindings
|
|
|
|
<p> bind $data(w:button) <1> "tixArrowButton:IncrCount $w"
|
|
}
|
|
|
|
<p>proc tixArrowButton:IncrCount {w} {
|
|
upvar #0 $w data
|
|
|
|
<p> incr data(count)
|
|
}
|
|
</pre></blockquote>
|
|
|
|
<p><H2><A NAME=6.5>6.5 Declaring and Using Variables</H2>
|
|
|
|
<p> The private variables of a widget class do not need to be
|
|
declared. In fact they can be initialized and used anywhere by any
|
|
method. Usually, however, general purpose private variables are
|
|
initialized by the <code> InitWidgetRec</code> method and subwidget
|
|
variables are initialized in the <code> ConstructWidget</code> method.
|
|
|
|
<p> We have seen in the <code> tixArrowButton:InitWidgetRec</code> example that
|
|
the private variable <code> data(count)</code> was initialized there. Also,
|
|
the private variable <code> data(w:button)</code> was initialized in <code>
|
|
tixArrowButton:ConstructWidget</code> and subsequently used in <code>
|
|
tixArrowButton:SetBindings</code>.
|
|
|
|
<p> In contrast, public variables must be declared inside the class
|
|
declaration. The following arguments are used to declare the public
|
|
variables and specify various options for them:
|
|
|
|
<p><blockquote><ul>
|
|
|
|
<p> <li> <code> -flag</code>: As shown in the class declaration in figure
|
|
<a href=oop.tex.html#6-2>6-2 </a>, the <code> -flag</code> argument declares all the public
|
|
variables of the TixArrowButton class, <code> -direction</code> and <code>
|
|
-state</code>
|
|
|
|
<p> <li> <code> -configspec</code>: We can use the <code> -configspec</code> argument to
|
|
specify the details of each public variable. For example, the
|
|
following declaration
|
|
|
|
<p><blockquote><pre>
|
|
-configspec {
|
|
{-direction direction Direction e}
|
|
{-state state State normal}
|
|
}
|
|
</pre></blockquote>
|
|
|
|
<p> <!ignored:nind> specifies that the <code> -direction</code> variable has the resource
|
|
name <code> direction</code> and resource class <code> Direction</code>; its default
|
|
value is <code> e</code>. The application programmer can assign value to
|
|
this variable by using the <code> -direction</code> option in the command
|
|
line or by specifying resources in the Tk option database with its
|
|
resource name or class. The declaration of <code> -state</code> installs
|
|
similar definitions for that variable.
|
|
|
|
<p> <li> <code> -alias</code>: The <code> -alias</code> argument is used to specify
|
|
alternative names for public variables. In our example, the setting
|
|
|
|
<p><blockquote><pre>
|
|
-alias {
|
|
{-dir -direction}
|
|
}
|
|
</pre></blockquote>
|
|
specifies that <code> -dir</code> is the same variable as <code>
|
|
-direction</code>. Therefore, when the application issue the command
|
|
|
|
<p><blockquote><pre>
|
|
.up config -dir w
|
|
</pre></blockquote>
|
|
it is the same as issuing
|
|
|
|
<p><blockquote><pre>
|
|
.up config -direction w
|
|
</pre></blockquote>
|
|
The <code> -alias</code> option provides only an alternative name for
|
|
the application programmer. Inside the widget's implementation code,
|
|
the variable is still accessed as <code> data(-direction)</code>, <i> not</i>
|
|
<code> data(-dir)</code>.
|
|
|
|
<p></blockquote></ul>
|
|
|
|
<p><H3><A NAME=6.5.1>6.5.1 Initialization of Public Variables</H3>
|
|
|
|
<p> When a widget instance is created, all of its public variables are
|
|
initialized by the Tix Intrinsics before the <code> InitWidgetRec</code>
|
|
method is called. Therefore, <code> InitWidgetRec</code> and any other
|
|
method of this widgte instance are free to assume that all the
|
|
public variables have been properly initialized and use them as
|
|
such.
|
|
|
|
<p> The public variables are initialized by the following criteria.
|
|
|
|
<p><blockquote><ul>
|
|
|
|
<p> <li> Step 1: If the value of the variable is specified by the
|
|
creation command, this value is used. For example, if the
|
|
application programmer has created an instance in the following way:
|
|
|
|
<p><blockquote><pre>
|
|
tixArrowButton .arr -direction n
|
|
</pre></blockquote>
|
|
The value <code> n</code> will be used for the -direction variable.
|
|
|
|
<p> <li> Step 2: if step 1 fails but the value of the variable is
|
|
specified in the options database, that value is used. For example,
|
|
if the user has created an instance in the following way:
|
|
|
|
<p><blockquote><pre>
|
|
option add *TixArrowButton.direction w
|
|
tixArrowButton .arr
|
|
</pre></blockquote>
|
|
The value <code> w</code> will be used for the <code> -direction</code> variable.
|
|
|
|
<p> <li> Step3: if step 2 also fails, the default value specified in
|
|
the <code> -configspec</code> secton of the class declaration will be used.
|
|
|
|
<p></blockquote></ul>
|
|
|
|
<p><H4><A NAME=6.5.1.1> Type Checker</H4>
|
|
|
|
<p> You can use a <i> type ckecker procedure</i> to check whether the user
|
|
has supplied a value of the correct type for a public variable. The
|
|
type checker is specified in the <code> -configspec</code> section of the
|
|
class declaration after the default value. The following code
|
|
specifies the type checker procedure <code> CheckDirection</code> for the
|
|
<code> -direction</code> variable:
|
|
|
|
<p><blockquote><pre>
|
|
-configspec {
|
|
{-direction direction Direction e CheckDirection}
|
|
{-state state State normal}
|
|
}
|
|
...
|
|
}
|
|
|
|
<p>proc CheckDirection {dir} {
|
|
if {[lsearch {n s w e} $dir] != -1} {
|
|
return $dir
|
|
} else {
|
|
error "wrong direction value \"$dir\""
|
|
}
|
|
</pre></blockquote>
|
|
Notice that no type checker has been specified for the <code> -state</code>
|
|
variable and thus its value will not be checked.
|
|
|
|
<p> If a type checker procedure is specified for a public variable, this
|
|
procedure will be called once the value of a public variable is
|
|
determined by the three steps mentioned above.
|
|
|
|
<p><H3><A NAME=6.5.2>6.5.2 Public Variable Configuration Methods</H3>
|
|
|
|
<p> After a widget instance is created, the user can assign new values
|
|
to the public variables using the configure method. For example, the
|
|
following code changes the <code> -direction</code> variable of the <code>
|
|
.arr</code> instance to <code> n</code>.
|
|
|
|
<p><blockquote><pre>
|
|
.arr configure -direction n
|
|
</pre></blockquote>
|
|
|
|
<p> In order for configuration to work, you have to define a
|
|
configuration method that does what the programmer expects. The
|
|
configuration method of a public variable is invoked whenever the
|
|
user calls the configure method to change the value of this
|
|
variable. The name of a configuration method must be the name of the
|
|
public variable prefixed by the creation command of the class and
|
|
<code> :config</code>. For example, the name configuration method for the
|
|
<code> -direction</code> variable of the TixArrowButton class is <code>
|
|
tixArrowButton:config-direction</code>. The following code implements
|
|
this method:
|
|
|
|
<p><blockquote><pre>
|
|
proc tixArrowButton:config-direction {w value} {
|
|
upvar #0 $w data
|
|
|
|
<p> $data(w:button) config -bitmap @$value.xbm
|
|
}
|
|
</pre></blockquote>
|
|
Notice that when <code> tixArrowButton:config-direction</code> is called,
|
|
the <code> value</code> parameter contains the new value of the <code>
|
|
-direction</code> variable but <code> data(-direction)</code> contains the <code>
|
|
old</code> value. This is useful when the configuration method needs to
|
|
check the previous value of the variable before taking in the new
|
|
value.
|
|
|
|
<p> If a type checker is defined for a variable, it will be called
|
|
before the configuration method is called. Therefore, the
|
|
configuration method can assume that the type of the <code> value</code>
|
|
parameter is got is always correct.
|
|
|
|
<p> Sometimes it is necessary to override the value supplied by the
|
|
user. The following code illustrates this idea:
|
|
|
|
<p><blockquote><pre>
|
|
proc tixArrowButton:config-direction {w value} {
|
|
upvar #0 $w data
|
|
|
|
<p> if {$value == "n"} {
|
|
set value s
|
|
set data(-direction) $value
|
|
}
|
|
|
|
<p> $data(w:button) config -bitmap @$value.xbm
|
|
return $data(-direction)
|
|
}
|
|
</pre></blockquote>
|
|
Notice the above code always overrides values of <code> n</code> to <code>
|
|
s</code>. If you need to override the value, you must do the following two
|
|
things:
|
|
|
|
<p><blockquote><ul>
|
|
|
|
<p> <li> Explicitly set the instance variable inside the configuration
|
|
method (the <code> set data(-direction) $value</code> line).
|
|
|
|
<p> <li> Return the modified value from the configuration method.
|
|
</blockquote></ul>
|
|
If you do not need to override the value, you don't need to return
|
|
anything from the configuration method. In this case, the Tix
|
|
Intrinsics will assign the new value to the instance variable for
|
|
you.
|
|
|
|
<p><H4><A NAME=6.5.2.1> Configuration Methods and Public Variable Initialization</H4>
|
|
|
|
<p> For efficiency reasons, the configuration methods are not called
|
|
during the intialization of the public variables. If you want to
|
|
force the configuration method to be called for a particular public
|
|
variable, you can specify it in the <code> -forcecall</code> section of the
|
|
class declaration. In the following example, we force the
|
|
configuration method of the <code> -direction</code> variable to be called
|
|
during intialization:
|
|
|
|
<p><blockquote><pre>
|
|
-forcecall {
|
|
-direction
|
|
}
|
|
</pre></blockquote>
|
|
|
|
<p><H2><A NAME=6.6>6.6 Summary of Widget Instance Initialization</H2>
|
|
|
|
<p> The creation of a widget instance is a complex process. You must
|
|
understand how it works in order to write your widget classes. The
|
|
following is the steps taken by the Tix Intrinsics when a widget
|
|
instance is created:
|
|
|
|
<p><blockquote><ul>
|
|
|
|
<p> <li> When the user creates an instance, the public variables are
|
|
intilized as discussed in section <a href=oop.tex.html#6.5.1>6.5.1 </a>. Type checkers
|
|
are always called if they are specified. Configuration methods are
|
|
called only if they are specified in the <code> -forcecall</code> section.
|
|
|
|
<p> <li> The <code> InitWidgetRec</code> method is called. It should initialize
|
|
private variable, possibly according to the values the public
|
|
variables.
|
|
|
|
<p> <li> The <code> ConstructWidget</code> method is called. It should create the
|
|
component widgets. It should also store the names of public
|
|
subwidgets into the subwidget variables.
|
|
|
|
<p> <li> The <code> SetBinding</code> method is called. It should create bindings for
|
|
the component widgets.
|
|
|
|
<p></blockquote></ul>
|
|
After the above steps, the creation of the instance is complete and the
|
|
user can iterate with it using its widget command.
|
|
|
|
<p><H2><A NAME=6.7>6.7 Loading the New Classes</H2>
|
|
|
|
<p> Usually, you can use a separate script file to store the
|
|
implementaion of each new widget class. If you have several of those
|
|
files, it will be a good idea to group the files into a single
|
|
directory and create a <code> tclIndex</code> file for them so that the new
|
|
classes can be auto-loaded.
|
|
|
|
<p> Suppose you have put the class files into the directory <code>
|
|
/usr/my/tix/classes</code>. You can create the <code> tclIndex</code> file using
|
|
the <code> tools/tixindex</code> program that comes with Tix:
|
|
|
|
<p><blockquote><pre>
|
|
cd /usr/my/tix/classes
|
|
/usr/my/Tix4.0/tools/tixindex *.tcl
|
|
</pre></blockquote>
|
|
|
|
<p> <!ignored:nind> The <code> tclIndex</code> file must be created by the <code> tixindex</code>
|
|
program. You cannot use the standard <code> auto_mkindex</code> command
|
|
that comes with Tcl.
|
|
|
|
<p> Once you have created the <code> tclIndex</code> file, you can use your new
|
|
widget classes by auto-loading. Here is a small demo program that
|
|
uses the new TixArrowButton class:
|
|
|
|
<p><blockquote><pre>
|
|
#!/usr/local/bin/tixwish
|
|
lappend auto_path /usr/my/tix/classes
|
|
|
|
<p># Now I can use my TixArrowButton class!
|
|
#
|
|
tixArrowButton .arr -direction n
|
|
pack .arr
|
|
</pre></blockquote>
|