First impressions with tcl/tk 8.5.0

2007-12-26 HE This days I tried tcl/tk 8.5 the first time. Here my experiences with 8.5.0 on Windows XP with eTcl.

:-) nice, good, I like it; :-| neutral; :-( not so good, I don't like it, makes additional work:

  • :-) Checkbuttons are tristate.
  • :-| But why is the new ttk::checkbutton not tristate? (JH: it is, from the docs: The widget sets the alternate state whenever the linked -variable is unset. (The alternate state may be used to indicate a tri-state or indeterminate selection.))
HE Sorry! The ttk::checkbutton docu says: to indicate a tri-state or indeterminate selection.
This means. The programmer can find out if the ttk::checkbox is in tristate.
But there is no simple way to set the ttk::checkbutton in a state, to show the user the tristate.
The normal checkbutton have a -tristatevalue. If the variable named by -variable is set to the
-tristatevalue, the user see a checked box with gray background (default on w32).
Perhaps this behavior can be simulate with ttk::checkbutton. But it's not in the docu. And I don't know how?
: So from my point of view
ttk::checkbutton is not tristate (or better, ttk::checkbutton doesn't show tristate)

Here is some example code demonstrating a ttk checkbutton's tristate display.

       checkbutton .c1 -variable c1 -onvalue a -offvalue b -tristatevalue c
       ttk::checkbutton .c2 -variable c2 -onvalue a -offvalue b

       pack .c1 .c2 -side left

       set c1 a ;# .c1 checked (on)
       set c1 b ;# .c1 unchecked (off)
       set c1 c ;# .c1 checked with grey background (tristate)

       set c2 a ;# .c2 checked (on)
       set c2 b ;# .c2 unchecked (off)
       unset c2 ;# .c2 checked with fill-dot check (tristate) [JH] - as noted above 
HE @JH In reality this is wrong. Unset c2 shows an empty checkbox. The application user can't see the tristate. Again! Tristate means for me, what the user see on the gui and not the internal state of the widget. And that is exact the difference between checkbox and ttk::checkbox.
EB Moreover, having the same -tristatevalue for both widgets would have been much better for compability.
HE Exact what I mean.
JH While -tristatevalue might make more sense for compatibility, the 'unset' state most certainly is correct visually with ttk::checkbutton (on XP at least).
HE @JH I find what you mean. The problem: I'm using XP with design classic. With this design the tristate isn't shown for ttk_checkbutton.
Changing the desktop to design 'Windows XP' and trying again shows the tristate. Changing the desktop back to design 'Windows classic' and trying once more, the tristate isn't shown. Tried this on two different machines.
Can someone confirm this?
HE 2008-01-07 Today I tried this on a w2000 SP4 maschine. The same effect: tristate isn't shown.
HE 2008-02-23 The problem is fixed in 8.5.1. The ttk::checkbutton behaves as documented with theme windows classic (if -variable is unset the ttk::checkbutton shows a grey background with a hook)
  • :-) {*} the reason why I tried 8.5.0
  • :-) lassign: I like the foreach-term but lassign looks faster:
       time {foreach {a b c} [list de da lus] {break}} 1000
       2.396 microseconds per iteration
       time {lassign [list de da lus] a b c} 1000
       1.632 microseconds per iteration
DKF: note that that's not a fair test of foreach; put each in a procedure or lambda term to test properly
HE I don't think the test is unfair. Both are one command, three variables, one list to generate with the same values, must be interpreted.
But for your reassurance:
       proc a {} {
              foreach {a b c} [list de da lus] {break}
              return
       }

       proc b {} {
              lassign [list de da lus] a b c
              return
       }

       time {a} 1000
       1.643 microseconds per iteration
       time {b} 1000
       1.234 microseconds per iteration
a. 1.643 / 2.396 => 68,6% time saved after bytecoded
b. 1.234 / 1.632 => 75,6% time saved after bytecoded
=> bytecoding saves ~70% time
=> lassign still looks faster
Is this what you mean?
IDG 1 ms total test time is probably a bit short for accurate timing. On my system I find
        (ian) 53 % time {a} 100000
        1.12969 microseconds per iteration
        (ian) 54 % time {b} 100000
        1.02071 microseconds per iteration
So b is still faster, but not so impressively
DKF: Yes. Wow; while I wrote that code, I didn't expect a speedup in this situation as lassign is implemented as a whole load of bytecodes and foreach has specialist ones. Might be worth rethinking the foreach compiler...
Duoas: I actually extended set to do lassign before I realized that lassign was just created... No matter the bytecodes used lassign will always be faster because it is a much simpler thing to do. foreach has to take into account a great deal more possibilities...
  • :-( text widget: What's that. Font has changed to a fixfont. And from a normal font to a named font (returnvalue from [.t configure -font] changed). First breaks the look and feel in some of my scripts and last breaks compatibility. I had to change my scripts.
    JH: [option add *Text.font TkDefaultFont] may be the easiest "revert", but there is also ::tk::classic::restore. he thank you for the hint. It would be easier if the help knows about this. I found ::tk::classic::restore in obsolete.tcl. So it means this is only a shortcut. The changes inside the scripts must be done in the future, too. And 'option add'?
From my point of view: Why this incompatibilities? So I (and a lot of other peoples) had to change the existing scripts/programs and a lot of additional testing. Why wasting this time. Isn't it better to add a command to each new script to change to the new behavior? This can be done on the fly and saves additional testing.
On an textwidget .t I can't change the font like in 8.4.16:
        .t configure -font "[.t cget -font] bold"
or
        .t configure tag configure title -font "[.t cget -font] bold"
Instead I must changed the code:
        proc cgetFont {win} {
            set font [$win cget -font]
            if {[llength $font] == 1} {
                set font [font configure $font]
            }
            return $font
        }
        .t configure -font "[cgetFont $::ausgabe] -weight bold"
or
        .t configure tag configure title -font "[cgetFont $::ausgabe] -weight bold"
This problem breaks code. Not only my own. For example viewIcons.tcl from the package ICONS
KPV the new idiom for this is:
        .t config -font [concat [font actual [.t cget -font]] -weight bold]
  • :-) New ttk::notebook and peer widgets for text. A small editor in 8.5.0 for tests. The peer widgets works fine.
  • :-( ttk::notebook: tabs changes their size and becomes unreadable when windows size shrink. I expected arrowbuttons like the BWidgets notebook. Or, as an alternative, breaking tabs in additional rows. The bwidget way works better on small displays like pocketPC.
  • :-) ttk::combobox: Works fine. Easy to replace the BWidget ComboBox.
  • :-( ttk::treeview: A small try:
       ttk::treeview .t -show tree
       pack .t -fill both -expand 1
       .t insert {} end -id 1 -text de
       .t insert 1  end -id 3 -text da
       .t insert 1  end -id 4 -text lus
       .t insert 4  end -id 5 -text ika
       .t insert 4  end -id 6 -text rus
       .t insert {} end -id 2 -text foo
I'm missing the lines like in BWidgets Tree. In little more complex trees without the lines the tree becomes unclear.
  • :-( Ok. At this point the new widgets in 8.5.0 are not ready to replace BWidget in my scripts.

This are my personal first impression. And it covers only a small part of the new features.


AM This seems a good place to add a link to Mark Roseman's overview of Tcl/Tk 8.5: [1 ]


2007-12-26 HE Some new impression:

  • :-) expression operators in and ni: Looks like a faster way:
       time {if {[lsearch -exact [list de da lus] {da}]!=-1} {}} 1000
       1.134 microseconds per iteration
       time {if {{da} in [list de da lus]} {}} 1000
       0.701 microseconds per iteration

       proc c {} {
              if {[lsearch -exact [list de da lus] {da}]!=-1} {}
              return
       }
       proc d {} {
              if {{da} in [list de da lus]} {}
              return
       }

       time {c} 1000
       1.417 microseconds per iteration
       time {d} 1000
       1.05 microseconds per iteration



       time {if {[lsearch -exact [list de da lus] {da}]==-1} {}} 1000
       1.132 microseconds per iteration
       time {if {{da} ni [list de da lus]} {}} 1000
       0.695 microseconds per iteration

       proc c {} {
                    if {[lsearch -exact [list de da lus] {da}]==-1} {}
              return
       }
       proc d {} {
              if {{da} ni [list de da lus]} {}
              return
       }

       time {c} 1000
       1.487 microseconds per iteration
       time {d} 1000
       1.05 microseconds per iteration
  • :-| Incr auto-initialization: The 'old' looks faster. The 'new' way looks better.
        unset n
        time {if {![info exists n]} {set n 0};incr n} 1000
        0.678 microseconds per iteration

        unset n
        time {if {![info exists n]} {set n 1} else {incr n}} 1000
        0.655 microseconds per iteration

        unset n
        time {incr n}
        8 microseconds per iteration
        unset n

        proc e {} {
                if {![info exists n]} {set n 0};incr n
                return
        }

        proc f {} {
                if {![info exists n]} {set n 1} else {incr n}
                return
        }

        proc g {} {
                incr n
                return
        }

        time {e} 1000
        0.921 microseconds per iteration
        time {f} 1000
        0.803 microseconds per iteration
        time {g} 1000
        1.864 microseconds per iteration
DKF: Two things happened in 8.5. Firstly, the semantics of incr were changed so that it's easier to write code that counts things (e.g. different words in a document). Secondly, info exists got it's byte-compiling stripes, making it much faster (previously it was embarrassingly slow due to working as a string-based command in a critical part of the implementation!)

IDG Dec. 28, 2007. tk_messageBox seems to use ttk buttons by default. This is ... surprising. Is there a simple way to cause reversion to the traditional look?

HE It looks like you are using a unix-like system. On this platforms tk_messageBox is mapped on tk::MessageBox (file lib\tk8.5\msgbox.tcl distributed but not used by tcl/tk on w32 systems). I don't know if someone would change this file to use no ttk-widgets. If you don't need the new parameter -detail, you can get an older version of the file msgbox.tcl from sourceforge [2 ] and replace the original file in your installation. If you can't change your installation you can source this file into your scripts. On w32 systems you also need to run

 proc ::tk_messageBox {args} {
        return [tk::MessageBox {*}$args]
 }

DKF: Or just run tk::MessageBox directly.

IDG It appears that that also uses themed buttons. There is no problem with new code. There may be a problem when old apps look different, and users don't like it. I thought the general philosophy with ttk in 8.5 was that you should get the old widgets unless you specifically asked for the new...

IDG Also tk_dialog seems to use unthemed buttons on Linux. Shouldn't tk_dialog and tk_messageBox be consistent in appearance?

HE This is my understanding too. But looking inside shows something different:

The default dialogs (used on unix-like systems in the files tkfbox.tcl, msgbox.tcl ...) using ttk-widgets but existing in namespace tk. This looks like a compromise between compatibility and platform look and feel. From my point of view it was better to use standard widgets for standard dialogs in namespace tk. If their is the need for theming dialogs, it is possible to create a second set (like the second set of widgets) in the namespace ttk.

More annoying: What sense makes packages if they are always loaded? Defining packages means for me loading code on demand not always.

I changed msgbox.tcl so it works without ttk-widgets. On XP it looks perfect. No need for the use of theming widgets. At least for me.

I think (and hope) their was a lot of discussions about this in the past. So I will try to live with this situation.

EB find this discussion funny. HE I woun't discuss. This are only my impressions. While ttk is an effort to make people stop saying Tk looks ugly, you are complaining on users of old applications who don't like it. HE I actually experienced just this in the company I'm working. Not with tk. But with changed look&feel. More in detail: The screenshot in documantation looks different as the application. This costs time to explain and change the documentation. Let the programmer the choice about the look & feel. It's easier to respect this in new scripts/application then changing the old one. Personaly, I find ttk is a big step forward. HE This is my meaning too. Not perfect but a big step I don't know one person (Tcl'er or not) saying Tk is worse than before. HE I never wrote this All my developments are done with 8.4/Tile since long time now, and a lot of people are surprised that it is written in Tcl/Tk. HE I got this reaction in the past even without Tile.

About the package require, anyway, all the ttk code is now in the tk library. And also note that Tk require msgcat.

  • :-| MHo: Shure I missed something... just installed ActiveState 8.5 on WinXP: I don't see anything installed beside the Tcl/Tk core files (no tcllib, BWidgets, Tclx and so on). And, no more tclsh.exe and wish.exe, just tclsh85.exe and wish85.exe in bin. Hm... Done this on two systems, on the first one without uninstalling the existing 8.4.16, on the second one first uninstalling. I also noticed the installer is several MB smaller that the 8.4.16-installer. RLH Copy tclsh85.exe to tclsh.exe and use teacup to install everything. This isn't the place for this btw.

    MHo: Know this is not the right place but I didn't find an answer to that elsewhere. And using teacup to install several MBs over a slow modem connection isn't really a choice. See Batteries Included for a discussion about that.

    Sly: I have installed ActiveState 8.5 on computer without access to internet. That was a very unpleasant surprise to have absolutely naked Tcl installation in contrast to 8.4. So where do I get all those 'batteries' for 8.5 now?..

    DKF: Best bet if you can't use teacup to pull the packages is to put the most recent 8.4 on first and ignore the warning about having two installs at once. (You might need to fix some paths and file associations by hand though.)

I am not sure this is the right place. I am a newbie to TCL (did some RealBasic many years ago) and I like to start programming again. Looked at TCL and installed ActiveTCL 8.5.0. To my suprise the demo>TK demo's are not working after a default install! I get an message saying "invalid command name mcset" and then some? Has anybody any idea what this means? -- JAR. RS Yes: you are probably in a locale, for which the message catalog is still in the old format (using mcset instead of ::msgcat::mcset). The files by language are in lib/tcl8.5/msgs. Thanks for your response. Changing the the contents of nl.msg in the ..\lib\tk85\demos directory(change mcset with ::msgcat::mcset) made the demo work. -- JAR.


JOB Tried out tk::treeview as a candidate for a replacement of the BWidget Tree object.

  • Couldn't find the source location of the "+" collapse/define icon (default in the source, style related ?).
  • Couldn't manage to re-adjust the item height - based on thumbnail images which I wanted to show at the beginning of each tree node (with the -image option).
  • style command is now ttk::style causing a lot of re-coding and it isn't possible to just use tk8.5 out of the box.

My 1st impressions so far: Tk8.5 looks very promising, especially anti-aliasing+ttk::* looks great... Although, existing programs 'll probably need a lot of rework to be prepared for ttk::* and style.


2008-01-29 HE

  • :-) incr n: if n doesn't exists, incr creates it. How many time I wrote code like this:
        if {![info exists files($el)]} {
            set n 1
        } else {
            incr n
        }
  • :-| this breaks code. Found a place in my code where I used
        if {[catch {
            incr n
        } ret]} { #some reaction)

2008-01-29 FB

  • :-) apply rocks! It should do wonders when combined with auto-expansion of leading words.
  • :-) I love dict of course. I wrote a dictionary package a couple years before TIP #111 [3 ] was written.
  • :-) lassign. I got tired of using foreach.
  • :-) Tk theme support. I wrote TIP #48 [4 ], but Tile/Ttk goes far beyond with script support.