Version 28 of A New Megawidget Library

Updated 2004-03-03 19:03:06

There have been lots of Mega-widget libraries written at different points in time, and all of them have their merits. I am currently thinking of writing a new mega-widget library which would be a re-write of all the BWidget code into a SNIT framework. I think the BWidget widgets are great. I just think making them leaves something to be desired.

Does anyone think this is worth the time and effort?

How would you go about writing a new mega-widget library?

What widgets would you include?

My hope is that this discussion could bring about a mega-widget library (and possibly a framework) which could become the benchmark for Tk. I want this to be the widget library you can't live without (currently BWidget for me). How would you do it?


DC 2004-02-26 - After a day of coding and some preliminary testing, I have the following to report.

I have rewritten the mega-widget functionality of SNIT into a smaller library (about 13k) from scratch. I didn't start with SNIT itself, just the functionality and syntax. Why didn't I just use SNIT? Because some people didn't want to depend on an external library, and SNIT was actually SLOWER than BWidgets.

....

NEM Sorry to interrupt, but surely the argument "some people didn't want to depend on an external library" is not a reason to write another external library? I'm really slightly confused as to what the difference is between snit and your code - surely neither is in the core, and so both are external libraries. snit is in tcllib, however. Wouldn't it be better to concentrate on submitting improvements to the snit maintainers?

....

With my new library in place, I took the ButtonBox widget from BWidgets and rewrote it in SNIT. The same exact code written for SNIT worked in the new library with no modifications. I then tested each implementation to get some rough benchmarks. All I did was create and destroy the button box 10000 times. This basically creates a frame widget and sets up the default options in each environment. And, for the record, the new framework creates a single ::megawidget namespace, and everything else is created under that, and it has the added bonus of handling options and error messages correctly so that a resulting mega-widget behaves exactly like a standard widget.

Here are the results (tested on a 2.4G Pentium with 512M RAM). Take them as you will:

    SNIT

    time "BBox .b; destroy .b" 10000
    822 microseconds per iteration

    BWidget

    time "ButtonBox .b; destroy .b" 10000
    570 microseconds per iteration

    New Megawidget Framework

    time "BBox .b; destroy .b" 10000
    360 microseconds per iteration

RS 2004-02-24 - First of all, "in contrast to Megahertz and Megabytes, a megawidget is not worth a million widgets". BWidget offers some popular things, like ComboBox, NoteBook etc., but custom "megawidgets" are often required. So make it easy on composing things - and best don't waste namespace names like BWidget does... For one-off usage, I often just pack or grid two or more things into a frame. Well, if it's the simplest thing that works...


DC 2004-02-25 - I don't see making a mega-widget framework without using namespaces. That's pretty much the clearest way to store information about a widget. And if it happens that we have a new namespace for each widget created, what's wrong with that? It will be destroyed when the widget is.

I did some preliminary testing by porting the BWidget ButtonBox to SNIT. The process was extremely painless, and I had the whole widget ported to a SNIT framework in about 10 minutes. This shows promise, as the whole BWidget library could be moved to SNIT with very little effort.

The only thing that might stop me is that when testing the two implementations, I found the BWidget actually faster. Not by much, but faster. About 500 microseconds per iteration faster. Anyone care to comment on that?


RS Namespaces are well and fine, but BWidget (and any successor) should claim a single ::BWidget namespace, and create child namespaces in that. Currently, after "package require BWidget; noteBook .n", the following are created:

 ::GlobalVar ::Widget ::DynamicHelp ::BWidget ::BWIDGET ::ArrowButton ::NoteBook

which is a bit much for me


Bryan Oakley 2004-02-25 - if it were me, I'd not base the widgets on snit. Snit is wonderful, but I personally believe megawidgets would be more universally accepted if they didn't depend on an external library.

As for namespaces, I think there should be a single toplevel namespace (eg: ::megawidget) with additional namespaces below that (eg: ::megawidget::combobox, ::megawidget::notebook, etc). Why? Good top-level namespaces are already being used by some widgets, and placing them all under an umbrella namespace will limit name clashes.

I've also found it convenient to create a namespace per widget but that's just my coding style. I tend to write code like this (not exactly, but this captures the spirit):

    proc mywidget {name args} {
        namespace eval ::mywidget::instance::$name {
            variable options 
            variable widgets
        }
        <create the widget...>
        interp alias {} $name {} ::mywidget::proxy $name
    }
    proc ::mywidget::proxy {name command args} {
        if {$command eq "configure"} {
            eval ::mywidget::configure $name $args
        }
    }
    proc ::mywidget::configure {name args} {
        variable ::mywidget::instance::${name}::options
        variable ::mywidget::instance::${name}::widgets
        ....
        $widgets(frame) configure -background $options(-background)
        ....
    }

I don't know if that's the most efficient way, but it works well in practice and means I don't need a large object system.

And yes, I know that snit is a wonderful mechanism to implement all the details of namespaces, instance variables, etc. I still find standalone widgets preferable to something that has external dependencies on an object system I might not otherwise require.

DC 2004-02-25 - Well, the idea is that whatever we end up with will become part of a core mega-widget library that can ship with the core and be depended-on to be there. I don't see any problem with SNIT being a candidate for that. If I write a mega-widget library from scratch, it's probably going to resemble SNIT in a lot of ways. Albeit, a lot smaller.

As of this writing, I've already gotten most of what I need done in about 11k of code. This mimics almost all of the SNIT functionality that we would need for a mega-widget library. Of course, someone will have an objection to distributing an extra 11k (probably 20k by the time I'm done) with the core. I just think we need mega-widget support as part of the core.


Isn't the new 'ensemble' stuff in Tcl 8.5 supposed to make all this easier? Shouldn't we be using that? If it's not quite adequate, shouldn't we extend it until it is? I also think a megawidget library would get more acceptance if it didn't rely on any specific object-model (of which Tcl's has a dozen or so, by now). Vince


DC 2004-02-25 - Well, that's what this page is for. What are the requirements of a mega-widget framework? I'm willing to do the leg work and make the library once we (those of us who develop mega-widgets, not just use them) decide what is required. We've all said that some amount of code at the core level is necessary to truly implement this kind of thing (IE: Adding -class options to all widgets, etc...), but I want to get something going now.

Maybe the ensemble code could be used. Is there a working patch of it anywhere? (Vince adds that the ensemble stuff is in Tcl 8.5 already -- the TIP is final, just read the namespace ensemble documentation)

I definitely like the idea of a single namespace and everything else is a child of that. That's kind of what got me started on a lot of this. Once the framework is in place, I plan to port BWidgets to the new framework as a starting point. My hope is that the framework itself would be distributed with the core, while the widget sets would be separate.


Peter Newman 2004-02-26: I don't know whether we need a new megawidget collection or not. But what we do need is inheritance and reusability. By that I mean that Tk widgets should be designed in such a way that there is a standard and well-documented method of adding new features, or replace existing features, of existing (core or complying,) widgets.

Take the button widget for example. Heaps of people have complained about the fact that you can't set a text only button's width/height in pixels (only in characters/lines). But rather than designing a new button from the ground up (as BWidgets and many other megawidget sets have done), a Tcl programmer should be able to correct this by either; adding a new (say) -pwidth/-pheight option to, or; replacing the existing -width/-height options of, the existing Tk button.

I realise that there are hacks to do this with current Tcl/Tk. But really it shouldn't be a hack. It should be a standard feature of Tk. Hopefully the "frameworks" and "object-oriented extensions" being talked about above, will include and make possible this sort of thing.

For example, we should be able to go:-

 button .mybutton -label {Hello World} ;
 pack .mybutton ;

 proc MyPixelWidthOptionHandler { ...whatever... } { ...whatever... } ;
 proc MyWidthOptionHandler { ...whatever... } { ...whatever... } ;
 .mybutton optionadd -pwidth MyPixelWidthOptionHandler ;
 .mybutton optionreplace -width MyWidthOptionHandler ;

In my opinion, coming to an agreement on a megawidget framework, then proceeding to generate a common set of megawidgets on that framework, provides the community with at least two things:

  • a source for useful widgets without having to code and debug them
  • source code examples for cases when the useful widgets do not quite meet the specifications

I'm uncertain whether a purely script based framework will scale appropriately; I keep remembering the rewrite of Tix from script to C, the struggles that the incr tcl community had with performance of incr widgets, etc.


DC 2004-02-26 - Well, the whole thing could certainly use some assistance from C. This is where the Tk core needs to have some features to support the making of mega-widgets. Obviously, any widget which is found to be extremely useful and in need of speed will eventually get converted to C (see: panedwindow, spinbox, labelframe), but that doesn't mean that Tcl developers shouldn't have the ability to develop their own widgets too. I, personally, hate writing things in C unless I really, really have to. Mostly because I can get it done really quickly in Tcl (that's why I use the language), and secondly because I don't have to recompile and then compile on every platform I want to support.

For this project to be truly useful, it needs support on both the C and the Tcl side. I'm looking to make a library of mega-widgets which can be distributed with the core (or at the very least, as the defacto standard). These widgets, over time, will most likely get moved into the core and be written in C as the need arises. The problem is that we don't often have the resources to make this happen as quickly as it is sometimes necessary.

Remember, 8.5 is supposed to be a revitalization of Tk. This whole idea is meant to support that effort.

Vince very much agrees with these last comments. This suggests that any new megawidget package should be written as, perhaps, a composition of two things:

  • a wrapper around Tk to emulate the stuff we'd like in C in the future (whatever that may be -- user data in widgets, better focus handling, etc)
  • a new megawidget package which makes use of the wrapper's functionality

WHD 2004-03-03: Some thoughts about Snit and the dependence of megawidgets on external libraries: de facto, any set of megawidgets is going to rely on some kind of megawidget framework. Users of the megawidgets shouldn't have to know about that framework--but surely it should be available for those who'd like to use it?

That said, I hate using packages that depend on other packages. But there's no reason why a megawidget set couldn't include a private copy of Snit, slightly modified to load into the megawidget set's namespace. Snit's implemented in such a way that two such copies could happily coexist.

It doesn't surprise me that Snit's slower than BWidget; it adds quite a lot of sugar, and sugar can be expensive. And to date, I've not had time or energy to do any amount of performance tuning--especially since I hope to reimplement Snit using ensembles when 8.5 is released.

A question for DC: Does your partial reimplementation of Snit pass the Snit test suite? There are many, many little details, especially regarding widget destruction, that are quite tricky to get right. But if it does, and it's faster, I'm not at all averse to updating Snit to use your techniques.

Also, you say your version produces widgets which look more like built-in widgets than Snit does--could you send me a list of the specifics?


Category GUI | Category Suggestions