Version 1 of 7GUIs

Updated 2015-02-15 03:20:06 by aspect

7GUIs is an interesting project to analyse the usability of different GUI toolkits. The 7 mini-application examples give focussed examples of important GUI patterns, such that the implementation should serve as a guide to how the language and toolkit under use help or hinder the programmer.

I expect some interesting Tk implementations to appear, perhaps leading to some discussions of where Tk is not so strong and how it could be improved.

Please add your implementations to this page, or critique ones already here. Adding a single solution (instead of all 7) is welcome, particularly if it highlights a beautiful technique. While showing off 3rd-party libraries is encouraged, at least one "naive Tk" implementation of each example should exist. Though for Cells I fully endorse the use of tablelist, purely on the assumption that no Tk programmer should be without it!

Naive Tk Implementations

These are intended to highlight how to use core Tcl/Tk features without relying on 3rd-party libraries. The code should be self-contained, though relying on bundled extensions such as ttk, sqlite3 is not discouraged and tcllib / tklib dependencies are not out of the question.

Enough "good practice" should be present to make the examples easy to extend or incorporate into a larger program without butchery. Thus doing everything inside a namespace, despite the extra verbosity of namespace which.

Counter

#!/usr/bin/env tclsh

package require Tk
package require lambda

namespace eval app {
    variable c 0
    entry .e -state readonly -textvariable [namespace which -variable c]
    button .b -text Count -command [lambda@ [namespace current] {} {
        variable c
        incr c
    }]
    pack .e .b -side left
    wm title . Counter
}

wm protocol . WM_DELETE_WINDOW exit
vwait forever

Temperature Converter

#!/usr/bin/env tclsh

package require Tk
package require lambda

namespace eval app {
    variable c 0
    variable f 32

    proc c2f {} {
        puts c2f
        variable c
        variable f
        set f [format %.1f [expr {$c * 9 / 5.0 + 32}]]
    }
    proc f2c {} {
        puts f2c
        variable f
        variable c
        set c [format %.1f [expr {($f - 32) * 5 / 9.0}]]
    }

    entry .c -textvariable [namespace which -variable c]
    entry .f -textvariable [namespace which -variable f]
    label .cl -text "\u00b0 Celcius"
    label .fl -text "\u00b0 Fahrenheit"

    trace add variable c write [lambda@ [namespace current] args c2f]
    trace add variable f write [lambda@ [namespace current] args f2c]

    pack .c .cl .f .fl -side left
}

wm title . "Temperature Converter"
wm protocol . WM_DELETE_WINDOW exit
vwait forever

Flight Booker

This is an example of dependent widgets (whose readonly status is a function of other widgets' values), which is fun with an approach like WJD's dynaforms (paper here ), but a little cumbersome in ordinary Tk (imo). Example Coming Soon.

Timer

Perhaps not the most efficient (tick does too much work when elapsed time is >100%), or most beautiful .. but already we're seeing that TclOO can make things much more pleasant, if only notationally:

#!/usr/bin/env tclsh

package require Tk
package require lambda

namespace eval app {

    variable percent 0
    variable started [clock milliseconds]
    variable seconds 0s
    variable duration 10.0

    proc reset {} {
        variable started
        set started [clock milliseconds]
    }

    proc tick {} {
        variable percent
        variable started
        variable seconds
        variable duration
        set now [clock milliseconds]
        set elapsed [expr {($now - $started) / 100 / 10.0}]
        set percent [expr {$elapsed * 100 / $duration}]
        if {$percent <= 100} {
            set seconds [format %.1fs $elapsed]
        } else {
            set started [expr {$now - int($duration * 1000)}]
        }
        after 100 [namespace which -command tick]
    }

    grid [
        label .pl -text "Elapsed Time:"
    ] [
        ttk::progressbar .p -variable [namespace which -variable percent] -orient h
    ] -sticky nsew

    grid [
        label .l -textvariable [namespace which -variable seconds]
    ] -sticky nsew

    grid [
        label .sl -text "Duration:"
    ] [
        scale .s -variable [namespace which -variable duration] -orient h -from 0.0 -to 15.0 -resolution 0.1 -showvalue 1
    ] -sticky nsew

    grid [
        button .r -text "Reset" -command [namespace which -command reset]
    ] - -sticky nsew

    wm title . Timer
    tick
}

wm protocol . WM_DELETE_WINDOW exit
vwait forever

Critique:

  * the [grid] code is repetitive and cumbersome to edit.  Layout should be more automatic for this kinda form.
  * lots of [variable] and [namespace] calls, which could be got rid of by moving to [TclOO]

Crud

Pretty sure we've all written more than plenty of these, but a concise, readable example will be fun.

Circle Drawer

A nice example to show how a simple [undo%|%http://wiki.tcl.tk/16681 ] facility can be built.

Cells

There are examples like A little spreadsheet and tiny spreadsheet all over the wiki, which could probably do with modernisation ... this is a good example for Tablelist or Tktable to shine.

Your Implementation