Version 1 of Designing SNIT widgets as mixins

Updated 2005-08-29 12:45:31 by escargo

A/AK The purpose of this page is to advocate one particular way of writing SNIT widgetadaptors. I think that this way deserves much more attention than it gets now by miscellaneous Snidget authors.

There is already a lot of useful Snidgets around. It won't take much time before it will become hard to choose between existing alternatives for a given function. Imagine that one text-based widget gives you a decent syntax highlighting, while another one lacks syntax highlighting but provides a wonderful find dialog, the third one has autoscrolling and syntax highlighting but... You've got it.

If there are n independent features that the standard text widget doesn't have, there may be 2^n-1 extended text widgets that implement different subsets of this features.

There is a way to extend existing widgets, fully supported by SNIT from the very start, that doesn't create such a mess. It's rather similar to the approach that many OO systems call mixins: when the particular instance of a class is enhanced in runtime with the functions coming from another class.

There is no extra effort needed to desing SNIT widget this way. First, we need to use snit::widgetadaptor instead of a snit::widget declaration. Many programmers seem to avoid using widgetadaptor when the hull widget is either frame or toplevel; but it is evident for me that the choice between widget and widgetadaptor should be made considering the nature of a widget, not only its hull type.

Second (supposed to be the main point of this page, actually), it's sometimes better to leave choosing actual hull type and creating hull widget out of the widgetadaptor. The widgetadaptor's constructor will look like this:

 constructor {args} {
     installhull $win
     $self configurelist $args
 }

This kind of widgetadaptor must be created when the hull widget already exists; when the widgetadaptor's instance is created, the existing widget suddenly gets new methods and/or options and functions.

It turned out to be very effective to design necessary addons for a particular widget type as independent pieces, implementing only a well-defined, highly-specialized function in each widgetadaptor. When you need some combination of those extensions in your application, it will be easy to write something like that:

 undoable [autocontextmenu [filecompletion [entry $path.ent]]]

where undoable, autocontextmenu and filecompletion is a name of your widgetadaptors adding miscellaneous features to an entry.

There's more than that. When you'll need to adapt a widget that is not an entry, but is much like an entry, no change in the widgetadaptor will be required usually:

 undoable [ttk::combobox $path.myCombobox]

(I actually have an "undoable" adapter for entries that runs unmodified with tile entries and various comboboxes).

Having a toolbox of widgetadaptors that don't enforce any predefined hull type is much like working with Unix environment. You don't have to choose between ls with integrated awk scripting and tcl interpreter and another ls that reads zip archives but lacks builtin awk: every tool does its own job, and they all are easily combined when a complex job must be done.


Category Design | Category Discussion