All pastes #304872 Raw Edit

Something

public text v1 · immutable
#304872 ·published 2007-01-04 16:18 UTC
rendered paste body
# voltmeter.tcl --
 #
 # 20060103 TJP can this be simplified & converted to tkinter? or used by tkinter?
 #  the simplification would begin with getting just 1 meter input  & 1 scale input and 1 quit button
 # begin by understanding it
 #
 # Part of: The TCL'ers Wiki
 # Contents: a voltmeter-like widget
 # Date: Fri Jun 13, 2003
 #
 # Abstract
 #
 #
 #
 # Copyright (c) 2003 Marco Maggi
 #
 # The author  hereby grant permission to use,  copy, modify, distribute,
 # and  license this  software  and its  documentation  for any  purpose,
 # provided that  existing copyright notices  are retained in  all copies
 # and that  this notice  is included verbatim  in any  distributions. No
 # written agreement, license, or royalty  fee is required for any of the
 # authorized uses.  Modifications to this software may be copyrighted by
 # their authors and need not  follow the licensing terms described here,
 # provided that the new terms are clearly indicated on the first page of
 # each file where they apply.
 #
 # IN NO  EVENT SHALL THE AUTHOR  OR DISTRIBUTORS BE LIABLE  TO ANY PARTY
 # FOR  DIRECT, INDIRECT, SPECIAL,  INCIDENTAL, OR  CONSEQUENTIAL DAMAGES
 # ARISING OUT  OF THE  USE OF THIS  SOFTWARE, ITS DOCUMENTATION,  OR ANY
 # DERIVATIVES  THEREOF, EVEN  IF THE  AUTHOR  HAVE BEEN  ADVISED OF  THE
 # POSSIBILITY OF SUCH DAMAGE.
 #
 # THE  AUTHOR  AND DISTRIBUTORS  SPECIFICALLY  DISCLAIM ANY  WARRANTIES,
 # INCLUDING,   BUT   NOT  LIMITED   TO,   THE   IMPLIED  WARRANTIES   OF
 # MERCHANTABILITY,    FITNESS   FOR    A    PARTICULAR   PURPOSE,    AND
 # NON-INFRINGEMENT.  THIS  SOFTWARE IS PROVIDED  ON AN "AS  IS" BASIS,
 # AND  THE  AUTHOR  AND  DISTRIBUTORS  HAVE  NO  OBLIGATION  TO  PROVIDE
 # MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 #
 # $Id: 9109,v 1.3 2003/06/17 08:00:45 jcw Exp $
 #

 package require Tcl 8
 package require Tk  8

 option add *borderWidth                                        1

 option add *Scale.from                                 0
 option add *Scale.to                                   110
 option add *Scale.orient                               vertical
 option add *Scale.label                                voltage
 option add *Scale.resolution                           1
 option add *Scale.showValue                            1

 proc main { argc argv } {
     global     forever

     wm withdraw .
     wm title    . "A voltmeter-like widget"
     wm geometry . +10+10

     voltmeter::constructor .t1 ::value1 { 0 50 100 }
     scale .s1 -command "set ::value1"

     #TJP option add *t2.label "Ampermeter (mA)"
     #TJP option add *t2.Canvas.width  80m
     #TJP option add *t2.Canvas.height 40m
     #TJP voltmeter::constructor .t2 ::value2 { 0 {} 2.5 {} 5 }
     #TJP scale .s2 -command "set ::value2"

     button .b -text Quit -command "set ::forever 1"

     #TJP grid .t1 .s1 .t2 .s2 .b
     grid .t1 .s1 .b

     wm deiconify .
     vwait forever
     voltmeter::destructor .t1
     #TJP voltmeter::destructor .t2
     exit 0
 }

#TJP this is like a struct
 namespace eval voltmeter {
     option add *Voltmeter.min                          0.0
     option add *Voltmeter.max                          100.0
     option add *Voltmeter.indexid                      {}
     option add *Voltmeter.ticksfont                    { Helvetica 8 }
     option add *Voltmeter.labelfont                    { Helvetica 9 }
     option add *Voltmeter.label                                "Voltmeter (V)"

     option add *Voltmeter.relief                       flat
     option add *Voltmeter.borderWidth                  0

     option add *Voltmeter.Canvas.background            gray
     #TJP width & height of widget? or just the area with the widget?
     option add *Voltmeter.Canvas.width                 200m
     option add *Voltmeter.Canvas.height                100m
     option add *Voltmeter.Canvas.foreground            black
     option add *Voltmeter.Canvas.highlightThickness    0
     option add *Voltmeter.Canvas.borderWidth           1
     option add *Voltmeter.Canvas.relief                raised

     variable   pi [expr {3.14159265359/180.0}]
 }

#TJP instantiator
 proc voltmeter::constructor { widget varname labels } {
     variable   pi
     upvar      $varname value

     frame $widget -class Voltmeter
     canvas [set c $widget.canvas]
     grid $c -sticky news -padx 2m -pady 2m

     option add ${widget}.varname $varname

     set font [option get $widget ticksfont {}]

     set width   [$c cget -width]
     set height  [$c cget -height]
     set xcentre [expr {$width*0.5}]
     set ycentre [expr {$width*1.4}]
     set t       1.15
     set t1      1.25

     $c create arc \
            [expr {$xcentre-$width*$t}] [expr {$ycentre-$width*$t}] \
            [expr {$xcentre+$width*$t}] [expr {$ycentre+$width*$t}] \
            -start 70.5 -extent 37 -style arc -outline lightgray\
            -width 0
     $c create arc \
            [expr {$xcentre-$width*$t}] [expr {$ycentre-$width*$t}] \
            [expr {$xcentre+$width*$t}] [expr {$ycentre+$width*$t}] \
            -start 71 -extent 36 -style arc -outline white \
            -width [expr {$ycentre*0.23}]
     $c create arc \
            [expr {$xcentre-$width*$t1}] [expr {$ycentre-$width*$t1}] \
            [expr {$xcentre+$width*$t1}] [expr {$ycentre+$width*$t1}] \
            -start 75 -extent 30 \
            -fill black -style arc -width 0.5m

     set num    [llength $labels]
     set angle  255.0
     set delta  [expr {30.0/($num-1)}]
     set l1     [expr {$width*$t1}]
     set l2     [expr {$width*$t1*0.95}]
     set l3     [expr {$width*$t1*0.92}]
     for {set i 0} {$i < $num} {incr i} {
        set a [expr {($angle+$delta*$i)*$pi}]

        set x1 [expr {$xcentre+$l1*cos($a)}]
        set y1 [expr {$ycentre+$l1*sin($a)}]
        set x2 [expr {$xcentre+$l2*cos($a)}]
        set y2 [expr {$ycentre+$l2*sin($a)}]
        $c create line $x1 $y1 $x2 $y2 -fill black -width 0.5m

        set x1 [expr {$xcentre+$l3*cos($a)}]
        set y1 [expr {$ycentre+$l3*sin($a)}]

        set label [lindex $labels $i]
        if { [string length $label] } {
            $c create text $x1 $y1 \
                    -anchor center -justify center -fill black \
                    -text $label -font $font
        }
     }

     set label  [option get $widget label {}]
     if { [string length $label] } {
        set font [option get $widget labelfont {}]
        $c create text $xcentre [expr {$ycentre-$width*1.05}] \
                -anchor center -justify center -fill black \
                -text $label -font $font
     }

     set value 0
     drawline $widget $value

     trace add variable $varname write \
            [namespace code "tracer $widget $varname"]
     return $widget
 }

#TJP destructor
 proc voltmeter::destructor { widget } {
     set varname [option get $widget varname {}]
     trace remove variable $varname write \
            [namespace code "tracer $widget $varname"]
     return
 }

#TJP draws the meter's needle
 proc voltmeter::tracer { widget varname args } {
     upvar      $varname value
     drawline $widget $value
     return
 }

#TJP draws a radial line from meter's pivot point with length of the needle, at angle calc'd from value
#TJP 'value' is a number between min & max, 
# and code here determines the ratio of value-min  to   max-min, 
# cnvrts that to grads, calcs the begin & endpoints, creates a line with those coordinates
 proc voltmeter::drawline { widget value } {
     variable   pi
     set id     [option get $widget indexid {}]
     set min    [option get $widget min {}]
     set max    [option get $widget max {}]

     set c $widget.canvas

     set v [expr { ($value <= ($max*1.05))? $value : ($max*1.05) }]

     set angle [expr {((($v-$min)/($max-$min))*30.0+165.0)*$pi}]

     set width  [$c cget -width]
     set xcentre        [expr {$width/2.0}]
     set ycentre        [expr {$width*1.4}]
     set l1     [expr {$ycentre*0.85}]
     set l2     [expr {$ycentre*0.7}]

     set xl [expr {$xcentre-$l1*sin($angle)}]
     set yl [expr {$ycentre+$l1*cos($angle)}]
     set xs [expr {$xcentre-$l2*sin($angle)}]
     set ys [expr {$ycentre+$l2*cos($angle)}]

     catch {$c delete $id}
     set id [$c create line $xs $ys $xl $yl -fill black -width 0.6m]
     option add *[string trimleft $widget .].indexid $id
     return
 }

 main $argc $argv

 ### end of file
 # Local Variables:
 # mode: tcl
 # page-delimiter: "^#PAGE"
 # End: