Creating new widgets
\c{
By virtue of the class structure and inheritance mechanism of C++
new widgets may easily be created.
An example is provided by the filechooser widget
provided by hush.
The filechooser widget merely groups an
entry, button and listbox in an appropriate way and
allows the user to install a handler to
retrieve the selected filename.
}
\sli{
interface filechooser : widget { \fbox{filechooser}
filechooser(); to create an exemplar (see section [creation])
filechooser(char* p, char * options = "");
filechooser(widget* w, char* p, char * options = "");
char* get();
};
}
\c{
The filechooser has been implemented by a mixture
of Tcl and C++ code.
In order to make the filechooser also
available as a widget to be used in Tcl scripts some
additional work is required.
Recall that, when creating a widget in Tcl/Tk,
the path name of the widget defines a command
that may be used to perform operations
(such as configure) on the widget, in an object-like
manner.
}
\c{
Dispatching
For a widget (not already defined by Tk) to act
as a command it must be able to figure
as a handler object, for which the
function dispatch is invoked whenever it is treated
as a command.
The dispatch function for the filechooser class
is shown below.
}
\sli{
private:
filechooser* f;
int dispatch( kit* tk , int argc, char** argv ) {
f = this;
if ( !strcmp("filechooser",*argv) )
return create(tk, --argc, ++argv);
argv++;
while ( argc-- > 1 ) {
if ( !strcmp("configure",*argv) )
return options(tk, argc,++argv);
else if ( !strcmp("get",*argv) ) { f->get(); return OK; }
else cout << " no such option " << endl;
argv++;
}
return OK;
}
}
\c{
In other words, the class filechooser combines three
roles, namely in the first place that of a widget class defining
the functionality of a widget, secondly
it implements the command filechooser that is used
to create a widget,
and thirdly it embodies the command associated
with (the path name of) the widget.
For the dispatch function there is an ambiguity
with respect to what object is referenced.
When creating a new widget, the object referenced
must still be created.
However, if the widget already exists it will
reference itself when treated as a command.
To resolve this ambiguity, an additional pointer
f is introduced that will reference the object
itself unless the reference is changed by
invoking create.
}
\sli{
int create(kit* tk , int argc, char** argv) {
f = new filechooser(*argv);
tk->action(*argv,f);
tk->result(*argv);
return options(tk,--argc,++argv);
}
}
\c{
The function create creates a new (filechooser) widget
and associates the path name of the widget
with an action taking the newly created
widget as the handler object.
Then (in conformance with Tk conventions)
it sets the result of the action to the
path name of the newly created widget.
}
\c{
Example
The filechooser widget command may now be used
in a same way as the standard Tk widget commands.
}
\sli{
filechooser .ff -command {puts stdout [.ff get]}
pack append . .ff {top}
go-back
}
\c{
In order to make the filechooser command available
as a Tcl command, an instance of filechooser
must be created to be associated with the
command of that name as a handler object.
}
\sli{
void install(kit* tk, int, char** ) {
handler* h = new filechooser;
tk->action("filechooser",h);
}
int main (int argc, char **argv) {
session* s = new session(argc,argv,"root");
s->install(install);
return s->run();
}
}
\c{
In the function main above, no
program function is given to run.
This restricts the executable to be useful
for interpreting scripts only.
When, after interpreting a script, also
a program function must be executed, the
script must contain the command go-back
as its last command.
}