[ulis], 2002-08-16, a little font chooser, tested under win2k only. [http://perso.wanadoo.fr/maurice.ulis/tcl/a_little_font_chooser.gif] LES on 2003-09-28 - Works for me on Win 98. [Googie], 2005-05-07, under X11 (Linux) looks fine too. ---- '''The chooser''' ############################### # # a pure Tcl/Tk font chooser # # by ulis, 2002 # # NOL (No Obligation Licence) # ############################### namespace eval ::choosefont \ { variable w .choosefont; variable font; # Martin Lemburg Aug. 20th, 2002 # initialization moved into proc choosefont # variable listvar; # # Martin Lemburg Aug. 20th, 2002 variable family; variable size; variable bold; variable italic; variable underline; variable overstrike; variable ok; variable lock 1; # ================ # choose a font # ================ # args: # f an initial (and optional) font # t an optional title # returns: # "" if the user aborted # or the created font name # usage: # namespace import ::choosefont::choosefont # choosefont "Courier 10 italic" "new font" namespace export choosefont; proc choosefont {{f ""} {t ""}} \ { # ------------------ # get choosefont env # ------------------ variable ::choosefont::w; variable ::choosefont::font; variable ::choosefont::listvar; variable ::choosefont::family; variable ::choosefont::size; variable ::choosefont::bold; variable ::choosefont::italic; variable ::choosefont::underline; variable ::choosefont::overstrike; variable ::choosefont::ok; variable ::choosefont::lock; # Martin Lemburg Aug. 20th, 2002 # refreshing, with every call, lsort added # set listvar [lsort -dictionary [font families]]; # # Martin Lemburg Aug. 20th, 2002 # ------------------ # dialog # ------------------ if {[winfo exists $w]} \ { # show the dialog wm deiconify $w; } \ else \ { # create the dialog toplevel $w; wm title $w "Choose a font"; # create widgets frame $w.f -bd 1 -relief sunken; label $w.f.h -height 4; label $w.f.l -textvariable ::choosefont::family; frame $w.fl; # Martin Lemburg Aug. 20th, 2002 # added selectmode setting # listbox $w.fl.lb \ -listvar ::choosefont::listvar \ -width 20 \ -yscrollcommand [list $w.fl.sb set] \ -selectmode single; # # Martin Lemburg Aug. 20th, 2002 scrollbar $w.fl.sb -command [list $w.fl.lb yview]; # Martin Lemburg Aug. 20th, 2002 # added underline options for mnemonics # frame $w.fa -bd 2 -relief groove; frame $w.fa.f ; label $w.fa.f.lsize -text size -underline 0; entry $w.fa.f.esize \ -textvariable ::choosefont::size \ -width 3 \ -validate focusout \ -vcmd {string is integer -strict %P}; checkbutton $w.fa.f.bold \ -text bold \ -underline 0 \ -variable ::choosefont::bold; checkbutton $w.fa.f.italic -text italic \ -underline 0 \ -variable ::choosefont::italic; checkbutton $w.fa.f.under \ -text underline \ -underline 0 \ -variable ::choosefont::underline; checkbutton $w.fa.f.over \ -text overstrike \ -underline 0 \ -variable ::choosefont::overstrike; # # Martin Lemburg Aug. 20th, 2002, frame $w.fb; button $w.fb.ok \ -text Ok \ -width 10 \ -command { set ::choosefont::ok 1 }; button $w.fb.cancel \ -text cancel \ -width 10 \ -command { set ::choosefont::ok 0 }; # bind events bind $w.fl.lb \ { set ::choosefont::family [%W get [%W cursel]] }; # Martin Lemburg Aug. 20th, 2002 # extended bindings # tk_focusFollowsMouse; # listbox handling bind $w \ { ::choosefont::selectfont %W First }; bind $w \ { ::choosefont::selectfont %W Last }; bind $w \ { ::choosefont::selectfont %W %K }; bind $w [list $w.fb.cancel invoke]; bind $w [list $w.fb.ok invoke]; # mnemonics bind $w \ { set w [winfo toplevel %W]; switch -exact -- [string tolower %K] \ { s {focus $w.fa.f.esize;} b {focus $w.fa.f.bold; $w.fa.f.bold invoke;} i {focus $w.fa.f.italic; $w.fa.f.italic invoke;} u {focus $w.fa.f.under; $w.fa.f.under invoke;} o {focus $w.fa.f.over; $w.fa.f.over invoke;} } } # # Martin Lemburg Aug. 20th, 2002 set lock 1; trace variable ::choosefont::family w ::choosefont::createfont; trace variable ::choosefont::size w ::choosefont::createfont; trace variable ::choosefont::bold w ::choosefont::createfont; trace variable ::choosefont::italic w ::choosefont::createfont; trace variable ::choosefont::underline w ::choosefont::createfont; trace variable ::choosefont::overstrike w ::choosefont::createfont; # place widgets grid $w.f -row 0 -column 0 -columnspan 2 -sticky nsew; grid $w.fl -row 1 -column 0 -padx 5 -pady 5; grid $w.fa -row 1 -column 1 -sticky nsew -padx 5 -pady 5; grid $w.fb -row 2 -column 0 -columnspan 2 -sticky ew -pady 20; grid $w.f.h -row 0 -column 0; grid $w.f.l -row 0 -column 1 -sticky nsew; grid $w.fl.lb -row 0 -column 0; grid $w.fl.sb -row 0 -column 1 -sticky ns; grid $w.fa.f -padx 5 -pady 5; grid $w.fa.f.lsize -row 0 -column 0 -padx 5 -sticky w; grid $w.fa.f.esize -row 0 -column 1 -sticky w; grid $w.fa.f.bold -row 1 -column 0 -columnspan 2 -sticky w; grid $w.fa.f.italic -row 2 -column 0 -columnspan 2 -sticky w; grid $w.fa.f.under -row 3 -column 0 -columnspan 2 -sticky w; grid $w.fa.f.over -row 4 -column 0 -columnspan 2 -sticky w; grid $w.fb.ok $w.fb.cancel -padx 20; }; # ------------------ # current font # ------------------ if {$f != ""} { set font $f }; if {![info exists font]} { set font [$w.f.l cget -font] }; set family [font actual $font -family]; set size [font actual $font -size]; set bold [expr {[font actual $font -weight] == "bold"}]; set italic [expr {[font actual $font -slant] == "italic"}]; set underline [font actual $font -underline]; set overstrike [font actual $font -overstrike]; set lock 0; ::choosefont::createfont; # ------------------ # end of dialog # ------------------ if {$t != ""} { wm title $w $t }; # Martin Lemburg Aug. 20th, 2002 - select current font # set newIndex [lsearch -exact $listvar $family]; $w.fl.lb selection set $newIndex; $w.fl.lb activate $newIndex; $w.fl.lb see $newIndex; # # Martin Lemburg Aug. 20th, 2002 vwait ::choosefont::ok; wm withdraw $w; if {$ok} \ { return [::choosefont::createfont] } \ else \ { return "" }; }; # ================ # ancillary procs # ================ proc selectfont {w mode} \ { if {[winfo class $w] != "Listbox"} \ { return; } set oldIndex [$w curselection]; if {[string length $mode] > 1} \ { switch -exact -- $mode \ { Down {set newIndex [expr {$oldIndex+1}];} Up {set newIndex [expr {$oldIndex-1}];} First {set newIndex 0;} Last {set newIndex end;} default \ { return; } } if {($newIndex != "end") && $newIndex} \ { if {$newIndex < 0} \ { set newIndex 0; } \ elseif {$newIndex > [$w size] - 1} \ { set newIndex end; }; } } \ else \ { set oldFamily [lindex $::choosefont::listvar $oldIndex]; if {[string match ${mode}* $oldFamily]} \ { set newIndex [expr {$oldIndex + 1}]; set newFamily [lindex $::choosefont::listvar $newIndex]; if {![string match ${mode}* $newFamily]} \ { set newIndex [lsearch \ -glob \ $::choosefont::listvar \ ${mode}* \ ]; } } \ else \ { set newIndex [lsearch \ -glob \ $::choosefont::listvar \ ${mode}* \ ]; }; if {$newIndex < 0} \ { return; }; }; set ::choosefont::family [$w get $newIndex]; $w selection clear $oldIndex; $w selection set $newIndex; $w activate $newIndex; $w see $newIndex; return; } proc createfont {args} \ { if {$::choosefont::lock} { return }; variable ::choosefont::w; variable ::choosefont::font; variable ::choosefont::family; variable ::choosefont::size; variable ::choosefont::bold; variable ::choosefont::italic; variable ::choosefont::underline; variable ::choosefont::overstrike; catch { font delete $font }; set f [list -family $family -size $size]; foreach {var option value} { bold -weight bold italic -slant italic underline -underline 1 overstrike -overstrike 1 } \ { if {[set $var]} { lappend f $option $value } }; $w.f.l config -font [set font [eval font create $f]]; return $font; } } ---- '''A demo''' # test namespace import ::choosefont::choosefont choosefont "Courier 10 italic" "new font" ---- '''Improvements''' [Martin Lemburg] August 20th, 2002: beautified a little bit by adding: * mnemomic bindings, e.g. Alt+b -> bold * keyboard bindings to the listbox, like cursor bindings and alphabetic bindings to jump quicker to a known font family by typing the first character * the Return- and Escape-binding for ok and cancel * a sorting of the font family list and a refresh of the font family list everytime the font chooser is called ---- '''Discussion''' Just a quick observation/question. Since newbies are going to be looking at the code, shouldn't the wiki adhere to the Tcl coding style and not breaking lines with slashes to do brace placing? [ulis] Your (anonymous) ''Tcl coding style'' is Kerningham's C style and I don't know any standard style for Tcl. I think the style I used is best suited for beginners showing clearly where blocs begin and end. [RLH] Can I agree with both? I would note that the books I have read and the documentation do not show the coding style above. So maybe that is what the poster meant by ''Tcl coding style''. [MG] Personally, I don't use that coding style (braces on the next line) like [ulis] does, and I'm still never quite familiar with it when I see it. But I don't think it can hurt having different styles on the Wiki; if you're serious about programming in Tcl (or any other language, for that matter), you're going to have to get used to seeing a LOT of different coding styles. No two people write code in the same way. Though, they should, since my coding style is obviously better than any other... ;) -- Well i am one of the newbies, and am curious, how this scripts finds out about the fonts on my linux machine? Which code part is it? [RS]: [font families] returns a list of all available fonts.- Another note: trailing semicolons are redundant in Tcl, and snippets like this if {$newIndex < 0} \ { return; }; }; can much simpler, and more idiomatically, be written as if {$newIndex < 0} return We should be glad that Tcl is not C :-) [GN] i use semicolons quite often in Tcl to allow multiple commands on one line (puts 1; puts 2; puts 3) [RS] True. But semicolons are statement separators in Tcl (just like newline), so to put them behind non-multiple commands is redundant. ---- [Googie] 2005-05-07 What about to change [entry] into [spinbox] from Tcl/Tk 8.4? Would be much more usable. ---- [schlenk] 2005-09-19 My version of this font chooser, with tile and msgcat support added and the controversial brace and semicolons removed. ############################### # # a pure Tcl/Tk font chooser # # by ulis, 2002 # # NOL (No Obligation Licence) # # # Basic Tile'ification and msgcat support # by schlenk, 2005 ############################### package require Tcl 8.4 package require Tk 8.4 package require msgcat package require tile 0.6 namespace eval ::choosefont { namespace import ::msgcat::mc namespace import ::ttk::* variable w .choosefont variable font # Martin Lemburg Aug. 20th, 2002 # initialization moved into proc choosefont # variable listvar # # Martin Lemburg Aug. 20th, 2002 variable family variable size variable bold variable italic variable underline variable overstrike variable ok variable lock 1 # ================ # choose a font # ================ # args: # f an initial (and optional) font # t an optional title # returns: # "" if the user aborted # or the created font name # usage: # namespace import ::choosefont::choosefont # choosefont "Courier 10 italic" "new font" namespace export choosefont proc choosefont {{f ""} {t ""}} \ { # ------------------ # get choosefont env # ------------------ variable ::choosefont::w variable ::choosefont::font variable ::choosefont::listvar variable ::choosefont::family variable ::choosefont::size variable ::choosefont::bold variable ::choosefont::italic variable ::choosefont::underline variable ::choosefont::overstrike variable ::choosefont::ok variable ::choosefont::lock # Martin Lemburg Aug. 20th, 2002 # refreshing, with every call, lsort added # set listvar [lsort -dictionary [font families]] # # Martin Lemburg Aug. 20th, 2002 # ------------------ # dialog # ------------------ if {[winfo exists $w]} { # show the dialog wm deiconify $w } else { # create the dialog toplevel $w wm title $w [mc "Choose a font"] # create widgets frame $w.f -bd 1 -relief sunken label $w.f.h -height 4 label $w.f.l -textvariable ::choosefont::family frame $w.fl # Martin Lemburg Aug. 20th, 2002 # added selectmode setting # listbox $w.fl.lb \ -listvar ::choosefont::listvar \ -width 20 \ -yscrollcommand [list $w.fl.sb set] \ -selectmode single # # Martin Lemburg Aug. 20th, 2002 scrollbar $w.fl.sb -command [list $w.fl.lb yview] # Martin Lemburg Aug. 20th, 2002 # added underline options for mnemonics # frame $w.fa -bd 2 -relief groove frame $w.fa.f label $w.fa.f.lsize -text [mc size] -underline 0 spinbox $w.fa.f.esize \ -textvariable ::choosefont::size \ -width 3 \ -validate focusout \ -vcmd {string is integer -strict %P} \ -from 1 \ -to 500 checkbutton $w.fa.f.bold \ -text [mc bold] \ -underline 0 \ -variable ::choosefont::bold checkbutton $w.fa.f.italic -text [mc italic] \ -underline 0 \ -variable ::choosefont::italic checkbutton $w.fa.f.under \ -text [mc underline] \ -underline 0 \ -variable ::choosefont::underline checkbutton $w.fa.f.over \ -text [mc overstrike] \ -underline 0 \ -variable ::choosefont::overstrike # # Martin Lemburg Aug. 20th, 2002, frame $w.fb button $w.fb.ok \ -text [mc Ok] \ -width 10 \ -command { set ::choosefont::ok 1 } button $w.fb.cancel \ -text [mc cancel] \ -width 10 \ -command { set ::choosefont::ok 0 } # bind events bind $w.fl.lb \ { set ::choosefont::family [%W get [%W cursel]] } # listbox handling bind $w \ { ::choosefont::selectfont %W First } bind $w \ { ::choosefont::selectfont %W Last } bind $w \ { ::choosefont::selectfont %W %K } bind $w [list $w.fb.cancel invoke] bind $w [list $w.fb.ok invoke] # mnemonics bind $w { set w [winfo toplevel %W] switch -exact -- [string tolower %K] { s {focus $w.fa.f.esize} b {focus $w.fa.f.bold $w.fa.f.bold invoke} i {focus $w.fa.f.italic $w.fa.f.italic invoke} u {focus $w.fa.f.under $w.fa.f.under invoke} o {focus $w.fa.f.over $w.fa.f.over invoke} } } # # Martin Lemburg Aug. 20th, 2002 set lock 1 trace variable ::choosefont::family w ::choosefont::createfont trace variable ::choosefont::size w ::choosefont::createfont trace variable ::choosefont::bold w ::choosefont::createfont trace variable ::choosefont::italic w ::choosefont::createfont trace variable ::choosefont::underline w ::choosefont::createfont trace variable ::choosefont::overstrike w ::choosefont::createfont # place widgets grid $w.f -row 0 -column 0 -columnspan 2 -sticky nsew -pady {2 20} grid $w.fl -row 1 -column 0 -padx 5 -pady 5 grid $w.fa -row 1 -column 1 -sticky nsew -padx 5 -pady 5 grid $w.fb -row 2 -column 0 -columnspan 2 -sticky ew -pady 20 grid $w.f.h -row 0 -column 0 grid $w.f.l -row 0 -column 1 -sticky nsew -pady 3 grid $w.fl.lb -row 0 -column 0 grid $w.fl.sb -row 0 -column 1 -sticky ns grid $w.fa.f -padx 5 -pady 5 grid $w.fa.f.lsize -row 0 -column 0 -padx 5 -sticky w grid $w.fa.f.esize -row 0 -column 1 -sticky w grid $w.fa.f.bold -row 1 -column 0 -columnspan 2 -sticky w grid $w.fa.f.italic -row 2 -column 0 -columnspan 2 -sticky w grid $w.fa.f.under -row 3 -column 0 -columnspan 2 -sticky w grid $w.fa.f.over -row 4 -column 0 -columnspan 2 -sticky w grid $w.fb.ok $w.fb.cancel -padx 20 } # ------------------ # current font # ------------------ if {$f != ""} { set font $f } if {![info exists font]} { set font [$w.f.l cget -font] } set family [font actual $font -family] set size [font actual $font -size] set bold [expr {[font actual $font -weight] == "bold"}] set italic [expr {[font actual $font -slant] == "italic"}] set underline [font actual $font -underline] set overstrike [font actual $font -overstrike] set lock 0 ::choosefont::createfont # ------------------ # end of dialog # ------------------ if {$t != ""} { wm title $w $t } # Martin Lemburg Aug. 20th, 2002 - select current font # set newIndex [lsearch -exact $listvar $family] $w.fl.lb selection set $newIndex $w.fl.lb activate $newIndex $w.fl.lb see $newIndex # # Martin Lemburg Aug. 20th, 2002 vwait ::choosefont::ok wm withdraw $w if {$ok} { return [::choosefont::createfont] } else { return "" } } # ================ # ancillary procs # ================ proc selectfont {w mode} \ { if {[winfo class $w] != "Listbox"} { return } set oldIndex [$w curselection] if {[string length $mode] > 1} { switch -exact -- $mode \ { Down {set newIndex [expr {$oldIndex+1}]} Up {set newIndex [expr {$oldIndex-1}]} First {set newIndex 0} Last {set newIndex end} default { return } } if {($newIndex ne "end") && $newIndex} { if {$newIndex < 0} { set newIndex 0 } elseif {$newIndex > [$w size] - 1} { set newIndex end } } } else { set oldFamily [lindex $::choosefont::listvar $oldIndex] if {[string match ${mode}* $oldFamily]} { set newIndex [expr {$oldIndex + 1}] set newFamily [lindex $::choosefont::listvar $newIndex] if {![string match ${mode}* $newFamily]} { set newIndex [lsearch \ -glob \ $::choosefont::listvar \ ${mode}* \ ] } } else { set newIndex [lsearch \ -glob \ $::choosefont::listvar \ ${mode}* \ ] } if {$newIndex < 0} { return } } set ::choosefont::family [$w get $newIndex] $w selection clear $oldIndex $w selection set $newIndex $w activate $newIndex $w see $newIndex return } proc createfont {args} { if {$::choosefont::lock} { return ""} variable ::choosefont::w variable ::choosefont::font variable ::choosefont::family variable ::choosefont::size variable ::choosefont::bold variable ::choosefont::italic variable ::choosefont::underline variable ::choosefont::overstrike catch { font delete $font } set f [list -family $family -size $size] foreach {var option value} { bold -weight bold italic -slant italic underline -underline 1 overstrike -overstrike 1 } { if {[set $var]} { lappend f $option $value } } $w.f.l config -font [set font [eval [linsert $f 0 font create]]] return $font } } package provide choosefont 0.1 # some translations for the msgcat support namespace eval ::choosefont { namespace import ::msgcat::mcset mcset de "ok" "Ok" mcset de "cancel" "Abbrechen" mcset de "bold" "Fett" mcset de "italic" "Kursiv" mcset de "underline" "Unterstrichen" mcset de "overstrike" "Durchgestrichen" mcset de "size" "Größe" mcset de "Choose a font" "Schriftart auswählen" } ---- [Category Example] | [Category GUI] | [Category Widget]