File: tk-spread.tcl

package info (click to toggle)
nsf 2.4.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 13,208 kB
  • sloc: ansic: 32,687; tcl: 10,723; sh: 660; pascal: 176; javascript: 135; lisp: 41; makefile: 24
file content (115 lines) | stat: -rw-r--r-- 3,042 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# A small Spreadsheet implementation, originally developed by Richard
# Suchenwirth in plain Tcl (see https://wiki.tcl-lang.org/1287). The
# spreadsheet was rewritten in an object oriented manner as a design
# study in NX by Gustaf Neumann in May 2011.
#
# image::tk-spread.png[]
#
package require Tk
package require nx::trait

 ##############################################################################
 # Class SpreadSheet
 #
 # The SpreadSheet computes simply totals for rows and columns.
 ##############################################################################
 nx::Class create SpreadSheet {
   #
   # The following attributes can be used for configuring the
   # spreadsheet.
   #
   :property {rows:integer 3} 
   :property {cols:integer 2} 
   :property {width:integer 8}
   
   #
   # If no widget is provided, use the name of the object as widget
   # name.
   #
   :property {widget ".[namespace tail [self]]"}

   #
   # Use the nx callback trait 
   #
   :require trait nx::trait::callback
   
   #
   # The method "cell" hides the internal respresentation and sets a
   # cell to a value.
   #
   :method cell {pair value} {
     set :data($pair) $value
   }
   
   #
   # The constructor builds the SpreadSheet matrix via multiple text
   # entry fields.
   #
   :method init {} {
     set :last ${:rows},${:cols}  ;# keep grand total field
     trace var [:bindvar data] w [:callback redo]
     frame ${:widget}
     for {set y 0} {$y <= ${:rows}} {incr y} {
       set row [list]
       for {set x 0} {$x <= ${:cols}} {incr x} {
	 set e [entry ${:widget}.$y,$x -width ${:width} \
		    -textvar [:bindvar data($y,$x)] -just right]
	 if {$x==${:cols} || $y==${:rows}} {
	   $e config -state disabled -background grey -relief flat
	 }
	 lappend row $e
       }
       grid {*}$row -sticky news
     }
     $e config -relief solid
   }
   
   # 
   # The method "redo" is triggered via the updates in the cells
   #
   :public method redo {varname el op} {
     if {$el ne ${:last}} {
       lassign [split $el ,] y x
       if {$x ne ""} {
	 :sum $y,* $y,${:cols}
	 :sum *,$x ${:rows},$x
       } ;# otherwise 'el' was not a cell index
     }   ;# prevent endless recalculation of grand total
   }
   
   #
   # The method "sum" adds the values matched by pattern (typically a
   # row or column) and sets finally the target column with the total
   #
   :method sum {pat target} {
     set sum 0
     set total "" ;# default if no addition succeeds
     foreach {i value} [array get :data $pat] {
       if {$i != $target} {
	 if {[string is double -strict $value]} {
	   set total [set sum [expr {$sum + $value}]]
	 }
       }
     }
     :cell $target $total
   }
 }

# Build spreadsheet "x"
SpreadSheet create x {
   # populate with some values
   :cell 0,0 Spread1 
   :cell 1,0 47
   :cell 2,1 11
 }

# Build spreadsheet "y"
SpreadSheet create y -rows 4 -cols 4 {
   :cell 0,0 Spread2
   :cell 1,0 12
   :cell 2,2 22
 }

# Pack the spreadsheets into one pane
pack [x cget -widget] [y cget -widget] -fill both