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_handler::dispatch} 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 operator() 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.