Dialogs
Interactive applications may require
the user to type some input
after reading a message or
to select an item from a list
of alternatives.
One of the widgets that may be used in a dialog
with the user is the filechooser
widget.
The filechooser widget consists
of a listbox filled with filenames
and an entry widget that contains
the filename selected by
the user (by double clicking on the name)
or which may, alternatively,
be used to type in a filename directly.
In addition, the filechooser
has an OK button, to confirm the choice
and a cancel button, to break off
the dialog.
Below, the construction of a simplified
version of the filechooser will
be discussed briefly.
Window-based interactive applications differ from
ordinary interactive applications
by relying on an event-driven flow of control.
The indirection that is typical for
event-driven control is exemplified
in the definition of the
{\em file_handler}
depicted in slide [class-filehandler],
that was invoked by the {\em file_menu}
in section [menus].
\slide{class-filehandler}{The {\em file_handler} class}{
.ds draw/file_handler.h
}
The {\em file\_handler} widget
Since the {\em file_handler} does not
correspond to an actual widget when created,
its constructor merely stores the
canvas pointer, which is actually a pointer
to the tablet.
In response to the Open or Save
menu entries, the {\em file_handler}
launches a {\em file_chooser}
and declares itself to be the
handler (with the appropriate arguments).
For example, when selecting the Open
entry, the {\em file_chooser} is launched
which eventually calls the {\em file_}
function
with OPEN as its argument.
The {\em file_handler} then invokes
the open function,
which results in reading in the file
and destroys the {\em file_chooser}.
In a similar way, the menu entry Save
results in writing the canvas to a postscript
file.
(The code for checking whether the
OK or cancel button is pressed
is left as an exercise.)
The {\em file\_chooser} widget
Despite its simple appearance,
which is left to the imagination of
the reader,
the {\em file_chooser} widget
has some subtle complexities.
\slide{class-filechooser}{The {\em file_chooser} class}{
class file_chooser : public toplevel {
file_chooser() : toplevel( gensym() ) { init(); }
int operator()();
char* get() { return e->get(); }
protected:
button* b; button *c; OK and cancel buttons
entry* e; listbox* l;
int install(char* s, action& a, char* opts);
void init();
void list();
}
}
A rudimentary {\em file_chooser} class
is depicted in slide [class-filechooser].
Typically, a filechooser
is a toplevel widget, that is a widget that
is independently mapped to the screen.
To avoid name clashes the function gensym,
which delivers a system-wide unique
name, is used to determine its path.
Apart from the function,
the {\em file_chooser} has only
one public function get,
which delivers the name selected or
typed in by the user.
The widget components of the
{\em file_chooser}, two buttons and
the entry and listbox widgets,
are stored in its instance variables.
Further, we have a function init
to construct the actual {\em file_chooser}
widget, a function list to fill
the listbox and the function install,
which is used to install an external handler
for the two button widgets.
The install function is defined as
void file_chooser::install(action& a, char* args) {
b->handler(a,args);
c->handler(a,args);
}
Recall, that when declaring a handler for
a button, the name of the button is given
as an additional argument when invoking the handler.
This enables the {\em file_handler}
to distinguish between a call due
to pressing the OK button and a call
due to pressing the cancel button.
The interplay between the C++ definition
and the underlying Tcl/Tk toolkit is nicely
illustrated by the definition of the list function.
void file_chooser::list() {
sprintf(buf,"foreach i [exec ls] { %s insert end $i }", l->path());
tk->eval( buf );
}
Calling list results in filling the
listbox with the filenames in the
current directory.
Its corresponding definition in C++
would, no doubt, be much more involved.
The init function constructs the
various component widgets
and an auxiliary frame widget to
obtain the desired layout.
It further defines the appropriate
event binding for the listbox, letting
double clicks result in setting the
entry.