if 0 { <> ---- **Introduction** [MiHa] 2015-05-13: This is a demo for a tcl/tk-program with all the essential GUI-elements. <
> It acts as a simple invoice-program with menu, entry-form and output (planned: one printed page). All the data is just strings of text, no validation, no calculation. With ideas and code from the following pages: * [grid] - "Basic Example" * [Ask, and it shall be given # 8] - "grid-layouts" - framework for data-entry * [m+] - Menu-creator by [RS] * [ClockDemo] - console & debugging * [Spider Solitaire], [TkOverload] - Help * [Displaying tables] * ... } ---- **Program 1** ======tcl # InvoiceDemo09.tcl - Mike Hase - 2015-05-13 / 2015-05-21 # http://wiki.tcl.tk/29284 # Simple "invoice"-themed GUI-demo, with menu, form for data-entry, output to screen and printer. # (output to printer is not done yet) package require Tk set Prog(Title) "Invoice-Demo" set Prog(Version) "v0.09" set Prog(Date) "2015-05-21" set Prog(Author) "Mike Hase" set Prog(HomePage) "http://wiki.tcl.tk/29284" set Prog(Contact) "me@example.com" set Prog(About) "A GUI-demo (disguised as an invoice-program:)\nPlus a printer-test." #---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+ global data maxFNr startF1 startF2 #set FieldNames1 {"Date " Title Name Street City Phone } set FieldNames1 { Title Name Street City Phone } #set FieldNames2 { art1Nr art1qty art1desc art1price price1 } #set FieldNames2 { Article-Number Quantity Description Price Total } set FieldNames2 { Item Description Unit-Price Quantity Amount } #---+----1----+----2----+ set fNr 0 set artNr 0 set lenLb 16 set lenEn 20 #: Boilerplate-text / Company-Address: set data(Adr1) "We have no T-Shirts Inc." set data(Adr2) "Marketplace 9" set data(Adr3) "Bigcity" set data(Adr4) "Somewhere" set data(Fon) "555-4321-0" set data(Fax) "555-4321-9" set data(Mail) "sales@noshirtsrequired.biz" #---+----1----+----2----+----3 # Build data-entry form: ## Todo: put this form into its own dialog #: Frame for customer-data: frame .f1 ;# -background red set field "Date" incr fNr set data($fNr) $fNr ;## Test set lb [label .f1.lb$field -text $field ] set en [entry .f1.en$field -width 10 -textvar data($fNr) ] grid $lb $en -padx 4 -pady 2 grid $lb -sticky e grid $en -sticky w set hdr [label .f1.lbHdr -text "Customer:"] grid $hdr -columnspan 2 -pady 8 foreach field $FieldNames1 { incr fNr set data($fNr) $fNr ;## Test set lb [label .f1.lb$field -width $lenLb -justify right -text $field ] set en [entry .f1.en$field -width $lenEn -justify left -textvar data($fNr) ] grid $lb $en -padx 4 -pady 2 grid $lb -sticky e grid $en -sticky w if { $fNr == 2 } { set startF1 $en } } #: Frame for article-data: # Same layout as above. Todo: place all fields for an article in one line frame .f2 ;# -background green incr artNr ;# Todo: extend to more articles set hdr [label .f2.hdr -text "Purchase:"] grid $hdr -columnspan 2 -pady 8 foreach field $FieldNames2 { incr fNr set data($fNr) $fNr ;## set lb [label .f2.lb$field -width $lenLb -justify right -text $field ] set en [entry .f2.en$field -width $lenEn -justify right -textvar data($fNr) ] grid $lb $en -padx 4 -pady 2 grid $lb -sticky e grid $en -sticky w #if { $startF2 == "" } { set startF2 $en } if { ![info exists startF2] } { set startF2 $en } } set maxFNr $fNr if 0 { ;# these buttons can be used as an alternative to the m+menu #: Frame for buttons: frame .f8 -background blue button .f8.b1 -text New -command { data0 } button .f8.b2 -text Test1 -command { data1 } button .f8.b3 -text Test2 -command { data2 } button .f8.b4 -text Show -command { showData2 } button .f8.b5 -text Print -command { printData } button .f8.b6 -text Exit -command { exit } grid .f8.b1 .f8.b2 .f8.b3 .f8.b4 .f8.b5 .f8.b6 pack .f1 .f2 .f8 -side top } pack .f1 .f2 -side top #---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+ # Menu: proc m+ {head name {cmd ""}} { #: Menu-creator "m+" by R.Suchenwirth and DKF, 2006-08-24, see http://wiki.tcl.tk/16327 # Uses the undocumented and unsupported feature ::tk::UnderlineAmpersand if {![winfo exists .m.m$head]} { foreach {l u} [::tk::UnderlineAmpersand $head] break .m add cascade -label $l -underline $u -menu [menu .m.m$head -tearoff 0] } if {[regexp ^-+$ $name]} { .m.m$head add separator } else { foreach {l u} [::tk::UnderlineAmpersand $name] break .m.m$head add command -label $l -underline $u -comm $cmd } } # GUI: define menu, bindings . configure -menu [menu .m] m+ &File &Open { Dummy "Open" } m+ &File &Save { Dummy "Save" } m+ &File ----- m+ &File &Exit exit m+ &Edit &Clear data0 m+ &Edit Testdata&1 data1 m+ &Edit Testdata&2 data2 m+ &Output &List showData2 m+ &Output &Show showData3 m+ &Output &Print printData m+ &Help &About About m+ &Help &Help Help m+ &Help ----- m+ &Help &Debug { console show } bind all Help bind all { console show } bind all bell bind all exit bind all data0 bind all data1 bind all data2 bind all showData2 bind all showData3 bind all printData #---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+ proc Dummy {txt} { #: Alert: "Function X not implemented yet" bell tk_messageBox -icon warning -title "Demo" \ -message "Function '$txt' not implemented yet." } proc About {} { #: Short info about the program global Prog set txt "$Prog(Title) $Prog(Version) - " append txt "$Prog(Date)\nby $Prog(Author) - $Prog(Contact)\n\n$Prog(About)" tk_messageBox -icon info -message $txt -title "About $Prog(Title) $Prog(Version)" } proc _Help {} { Dummy Help } ;# needs work proc Help {} { global Prog set w .help if { [winfo exists $w] } { wm deiconify $w raise $w focus $w return; } toplevel $w wm title $w "$Prog(Title) - Help" frame $w.f text $w.f.t -wrap word scrollbar $w.f.sb $w.f.t configure -yscrollcommand "$w.f.sb set" $w.f.sb configure -command "$w.f.t yview" $w.f.t tag configure h1 -font {{} 18 bold} -justify center -foreground red $w.f.t tag configure h2 -font {{} 14 italic} -justify center $w.f.t tag configure h3 -font {{} 10 bold } $w.f.t insert end "$Prog(Title)\n" h1 $w.f.t insert end "Version $Prog(Version)\n\n" h2 $w.f.t insert end "$Prog(Title) is a GUI-demo that acts as a simple invoice-program.\nThere is a form for data-enty, and output of that data to screen and printer.\n\n" $w.f.t insert end "HOTKEYS:\n" h3 $w.f.t insert end "* F1 - Show this help.\n* F2 - Activate Debug/Console.\n* F4 - Exit program.\n" $w.f.t insert end "* F5 - Edit: Clear entry-fields.\n* F6, F7 - Edit: Fill entry-fields with testdata.\n" $w.f.t insert end "* F9 - Output data to screen.\n\n" $w.f.t insert end "DEBUG:\n" h3 $w.f.t insert end " The console offers access to the program's internals and variables.\n\n" $w.f.t insert end "Commands:\n ?: show console-help, e: Exit program.\n" $w.f.t insert end " d0: Clear entry-fields. d1, d2: Fill-in testdata.\n" $w.f.t insert end " s0, s1, s2, s3: Show data in different formats.\n\n" $w.f.t insert end "You can enter any tcl-command in the console, for example:\n" $w.f.t insert end "% info proc\n" $w.f.t insert end "% info var\n" $w.f.t insert end "% puts \$maxFNr\n" $w.f.t insert end "% parray data\n" $w.f.t insert end "% set data(3) \"Johnson\"\n" $w.f.t insert end "\n" $w.f.t insert end "CREDITS:\n" h3 $w.f.t insert end "Written by $Prog(Author) ($Prog(Contact)), source at: $Prog(HomePage).\n" $w.f.t configure -state disabled pack $w.f -side top -expand 1 -fill both pack $w.f.t -side left -expand 1 -fill both pack $w.f.sb -side right -fill y frame $w.f2 pack $w.f2 -side top -pady 8 button $w.f2.b -text "Close" -command "wm withdraw $w" -width 9 pack $w.f2.b wm protocol $w WM_DELETE_WINDOW "wm withdraw $w" focus $w.f.t };# Help #---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+ # Routines to edit/fill in data: proc data0 {} { #: Clear data in entry-fields for {set f 1} {$f <= $::maxFNr} {incr f} { set ::data($f) "" } #set ::data(1) "2015-05-20" set cs [clock seconds] set td [clock format $cs -format "%Y-%m-%d"] set ::data(1) "$td" focus .f1.enDate } proc data1 {} { #: Fill entry-fields with testdata set ::data(1) "2015-05-13" set ::data(2) "Mr." set ::data(3) "Smith" set ::data(4) "Mainstreet 123" set ::data(5) "Newtown" set ::data(6) "555-6789" set ::data(7) "0815" set ::data(8) "T-Shirt ultrablack, size XL" set ::data(9) " 9.99" set ::data(10) "2" set ::data(11) "19.98" focus $::startF1 } proc data2 {} { #: Fill entry-fields with testdata set fNr 0 set values { "2015-05-14" "Mrs." "Miller" "Highstreet 99" "Oldsville" "555-9876" "0816" "T-Shirt XL" "12.34" "1" "12.34" } foreach v $values { incr fNr set ::data($fNr) $v } focus $::startF2 } #---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+ # Output-Routines: proc showData0 {} { puts "INVOICE-data:" parray ::data } proc showData1 {} { #: Show the data on the console global data maxFNr puts "INVOICE\n==" for {set f 1} {$f <= $maxFNr} {incr f} { puts "Field#$f : $data($f)" } puts "--\nTHANKS !" } proc showData2 {} { #: Show the data in a simple messagebox global data maxFNr set txt "INVOICE\n==\n" for {set f 1} {$f <= $maxFNr} {incr f} { append txt "Field#$f : $data($f)\n" } append txt "--\nTHANKS !" tk_messageBox -icon info -message $txt -title "ShowData2" } proc showData3 {} { ;# from: TkOverload Help #: Show the data formatted like an invoice-letter global data catch {destroy .dia} toplevel .dia wm title .dia "Invoice" wm geom .dia "+[expr {[winfo x .] + [winfo width .] + 10}]+[winfo y .]" text .dia.t -relief raised -wrap word -width 70 -height 23 \ -padx 10 -pady 10 -cursor {} -yscrollcommand {.dia.sb set} scrollbar .dia.sb -orient vertical -command {.dia.t yview} button .dia.dismiss -text Dismiss -command {destroy .dia} pack .dia.dismiss -side bottom -pady 10 pack .dia.sb -side right -fill y pack .dia.t -side top -expand 1 -fill both set bold "[font actual [.dia.t cget -font]] -weight bold" set italic "[font actual [.dia.t cget -font]] -slant italic" .dia.t tag config h1 -justify center -foregr blue -font "Times 20 bold" .dia.t tag configure h2 -justify left -font "Times 12 bold" .dia.t tag configure bold -font $bold .dia.t tag configure ital -font $italic .dia.t tag configure n -lmargin1 15 -lmargin2 15 .dia.t insert end "Invoice\n" h1 # Todo: place picture with logo here set m "--- --- --- --- --- ---\n\n" .dia.t insert end "From:\n" h2 .dia.t insert end "$data(Adr1)\n$data(Adr2)\n$data(Adr3)\n$data(Adr4)\n" bold $m .\n\n .dia.t insert end "To:\n" h2 .dia.t insert end "$data(2) $data(3)\n$data(4)\n$data(5)\n" bold $m .\n\n # Todo: tweak formatting #.dia.t insert end "Item Description Unit Price Quantity Amount\n" bold $m n foreach field $::FieldNames2 { .dia.t insert end "$field " bold } .dia.t insert end "\n" #set m "$data(8) x $data(7) $data(9) -- $ $data(10) ea. = $ $data(11)\n" set m "$data(7) $data(8) $data(9) * $data(10) = $ $data(11)\n" .dia.t insert end $m n set m "$ $data(11)\n\n" .dia.t insert end "Total:\n" bold $m n set m "" append m "This product is meant for educational purposes only. " append m "Keep away from fire or flames. " append m "For recreational use only. " append m "Some assembly required. " append m "Do not use while operating a motor vehicle or heavy equipment. " append m "Any resemblance to real persons, living or dead is purely coincidental. " append m "Avoid contact with skin. " append m "No other warranty expressed or implied. " append m "One size fits all. " append m "Do not disturb. " append m "Action figures sold separately. " append m "Batteries not included. " append m "Price does not include taxes. " append m "Use only as directed. " append m "Keep away from sunlight. " append m "All rights reserved. " append m "Keep cool. \n" .dia.t insert end "Standard Disclaimer\n" bold $m n .dia.t config -state disabled focus .dia.t } # Todo: proc printData {} { Dummy printData } #---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+ #: Test+Debug: proc ? {} { help } proc help {} { puts "\n$::Prog(Title) $::Prog(Version)" puts "--" puts "argv0 : $::argv0" puts "argv : $::argv" puts "tcl/tk: $::tcl_patchLevel / $::tk_patchLevel \n" puts "d0,d1,d2, s0..s3:data0,data1,data2, showData0..3 ?:help e:exit \n" } proc d0 {} { data0 } proc d1 {} { data1 } proc d2 {} { data2 } proc s0 {} { showData0 } proc s1 {} { showData1 } proc s2 {} { showData2 } proc s3 {} { showData3 } proc e {} { exit } #---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+ #: Main: wm title . "$Prog(Title) $Prog(Version)" help # Todo: make and include an icon here if {[file exists demo.ico]} { wm iconbitmap . demo.ico } focus -force . ### EOF ### ====== Example icon: [InvoiceDemo_icon] It looks like the upload-procedure of the wiki doesn't like .ico - files. <
> So, just copy any icon you like to the location of the program, and rename it to demo.ico ---- **Output** Dump of the contents of the entry-fields, filled with testdata: ======none INVOICE == Field#1 : 2015-05-13 Field#2 : Mr. Field#3 : Smith Field#4 : Mainstreet 123 Field#5 : Newtown Field#6 : 555-6789 Field#7 : 0815 Field#8 : T-Shirt ultrablack, size XL Field#9 : 9.99 Field#10 : 2 Field#11 : 19.98 ====== ---- **Remarks** '''MiHa''': This is a nice small demo of a simple program using only basic, essential GUI-features: * Menu * Buttons (to see them, change that "if 0"-section to "if 1") * Hotkeys (F1..F9, etc.) * Labels * Entry-fields * Messagebox * Title at top of window * Icon at top of window (currently, this needs an external file) * [frame]s, [pack] and [grid] to manage the layout There is lots of more advanced GUI-stuff not covered so far, e.g.: * Checkboxes * Radiobuttons * Fancy textformating, [font]s (i.e. for a nice help-window) * http://wiki.tcl.tk/1437%|%Listbox%|% / [Multicolumn listbox] / [Tables] * Scrollbars * dialog-windows separate from the main-window (i.e. for the data-entry form) But if any of that gets included, and the program gets more complex because of that, <
> it might be better to put that into a separate program. The data is just simple strings of text, all of the same length, no validation, no calculation, no special logic, etc. <
> This definitely needs work for any real-world application. <
> BTW, I haven't found yet any good, nice, short routine for data-entry (such as m+ for menus). Well, I tried to do a bit here: * Date as a single entry-field * Customer- and purchase-data separated with a label above each one The size of the grid-columns and the alignment of the labels in these separated sections don't match any more, <
> To keep the layout looking good requires tweaking. <
> That means the code there quickly gets complicated and hard-to-understand. <
> This is not good for demo that should be easy-to-understand. Also, there is no file-I/O for data or configuration. I haven't looked into the printing stuff yet, so if anybody thinks he is up to the task, you are welcome to fill in that part. ---- **See also** * [GUI Primer] - essentially my notes researching GUI-stuff on tcl/tk !!!!!! !!!!!! * http://wiki.tcl.tk/10705%|%Category Printing%|% - from that, some selected pages: ** [printing] - mostly discussion ** [Things holding Tcl back] <
> <
> ** [Printing under Windows] - not platform-independent ** [Printing text files under Windows] - using workarounds like exec, print, type, notepad ** [Printing a canvas under Windows] - using external utilities, via postscript or pdf *** [Printing a canvas using GhostScript] ** [Printing a text file to a lpr printer] - using filesystem/network/sockets ** [tclcups] - (page is in french ?) <
> <
> ** [Tcl/Tk Printing Support] - discussion and wishlist / GSoC 2009 *** http://wiki.tcl.tk/22182#pagetoc90d3f90b%|%GSoC 2009 - Printing%|% *** http://wiki.tcl.tk/22182#pagetoc66706faf%|%GSoC 2009 - Cicero refurbish%|% *** http://wiki.tcl.tk/22182#pagetoc3f61176f%|%GSoC 2009 - Glade Project%|% ** [Krzysztof Blicharski] - worked on "Tcl/Tk Printing Support" GSoC project (but no details there) ** [GSoC 2009 Executed Projects] - status "ok", but no details or links *** http://code.google.com/p/google-summer-of-code-2009-tcl/downloads/list *** http://svn.assembla.com/svn/tktopdf - "tk-to-pdf", Revision 154, 2009-08-18. <
>It looks like nobody cared after the project reached that point. ** [TkPrint] - List of several packages: *** http://pages.videotron.com/cclients/files/tkprint1.1.html%|%Tkprint 1.17%|% - 2002-02 "Tcl/Tk Extensions for Windows", "Free for non-commercial use" *** http://pages.infinit.net/cclients/files/tkprint1.1.html%|%Tkprint 1.17%|% - same as above, but other webpage ** http://www.schwartzcomputer.com/tcl-tk/tcl-tk.html - For Windows & Unix, Version: 0.9.6.15 - 27 May 2009 All in all, it looks like printing from Tcl/tk in a "native, portable way" is kind of a hard problem, and still mostly unsolved. <> Example | GUI