From: Bruce on
Bob wrote:
> Ok, you certainly have more patience than I do. ;) ;)
>
> Here is the last iteration of many that I have tried. As I said, I am
> pretty much chasing my tail at this point, so this may not be the code that
> came closest to working. It is also stripped down to the point to just deal
> with these variable issues I have been having. (BTW, is there any way to
> just make a variable visible >from anywhere< >to anywhere< in the code?
> The program I have in mind is not going to be so complex as to have to
> protect variables.

no - variable in a aproc default to local scope - use global to access
global variables within a proc (code outside any proc is running in
global scope already) if you don;t want to use tyhe global command you
can allways be explicit and preace your vars with :: (like $::dit)

also you can use a array for all you valss o you only need to declare
one variable

e.g.

global GVars

set GVars(dit) 1
set GVars(dah) 5
set GVars(space) 3

>
> #############################################################################
> proc wpmcalc {wpm} {
> set wpmper [expr {($wpm*.01)}]
> }

this function only sets the local variable wpmper inside the proc
which immediatley leaves scope so is pointless
>
> proc init {} {
> global dit dah space wpm ditlen wpmper
>
> }

global command doesn't create any variables, only defines those
varnames in the global scope for the current proc - so you
probably want

set dit 1
set dah 5
set space 3
set ditlen 1
set wpm 100
set wpmper 1.0

inside that proc to actually define the values

>
> init
>
> scale .dit -orient horizontal -label dit -variable dit
> scale .dah -orient horizontal -label dah -variable dah
> scale .space -orient horizontal -label space -variable space
> scale .wpm -orient horizontal -label wpm -from 80 -to 100 -variable
> wpm -command wpmcalc
>
> pack .dit
> pack .dah
> pack .space
> pack .wpm
>
> set ditlen [expr {int($dit*$wpmper)}]
>
> ##############################################################################
>
> When all is said and done, I want 4 scale bars:
>
> One that will control the length of a dit. (call it dit)
> One that will control the length of a dah (call it dah)
> One that will control the length of a space between the other two elements.
> (call it space)
> One that will provide a value (0.8 to 1) that will be multiplied with each
> of the other values, so as to increase or decrease all of them by the same
> relative amount. (call it wpm or more accurately "speed")
> (A related issue....this is where the 'wpm*0.01' code comes in....I also
> struggled with how to make a scale bar go from 0.8 to 1.0, so I gave up and
> went from 80 to 100).

make sure you set the -resolution option or it default to 1 and rounds
all values so you get a scale of 1 to 1 (the -digits option can be used
to display them


do you ever need the raw values of dit/dah/space? or only the modified
values?

if you only need the final values then the follwoing should get you going:

Bruce



proc build_gui {} {
scale .dit -orient horizontal -label dit -command updateVars
.dit set 1
scale .dah -orient horizontal -label dah -command updateVars
.dah set 3
scale .space -orient horizontal -label space -command updateVars
.space set 2
scale .wpm -orient horizontal -label wpm -from 0.80 -to 1.0 \
-resolution 0.01 -command updateVars
.wpm set 1.0

pack .dit
pack .dah
pack .space
pack .wpm

button .b -text "Try Me" -command sample
pack .b

# init values from scales
updateVars
}


proc updateVars {args} {
global Vars
set Vars(dit) [expr [.dit get] * [.wpm get]]
set Vars(dah) [expr [.dah get] * [.wpm get]]
set Vars(space) [expr [.space get] * [.wpm get]]

puts "New Values are: --------------"
parray Vars
puts "-------------------------------"
}

proc sample {} {
global Vars

puts ""
puts "Currently dit is $Vars(dit)"
puts "$::Vars(dah) is the value of dah"
puts ""
}

build_gui
From: Aric Bills on
Bruce gave you some specific pointers with your code, so I won't go
there, but let me explain a bit more about Tcl's variable scope model,
which differs in some crucial respects from scope in most other
languages. To answer your question about making a variable visible to
anywhere from anywhere, the short answer is yes, but not in the same
way you'd do it in C or a similar language. In C, you declare a
variable global. In Tcl, you use qualified namespace variables, or
you use convenience commands like [global] or [variable] that allow
you to use unqualified names for namespace variables.

In Tcl there are two types of variables: namespace variables and
procedure variables. Namespace variables persist until they are
explicitly destroyed, or until the Tcl interpreter in which they are
defined is destroyed. Procedure variables persist only during the
lifetime of the procedure in which they were declared. Within a
procedure, variable names are treated as local (procedure) variables
unless they contain namespace qualifiers (look up the namespace man
page for more info), or unless, within that procedure, those variable
names were declared to resolve differently. Two commands that change
how variable names resolve within a procedure are [global] and
[variable]. [global] declares that the following variable names refer
to variables in the global namespace. [variable] declares that the
listed variables should be linked to variables in the namespace that
the procedure belongs to (all procedures belong to a namespace; so
far, you've probably only created procedures in the global
namespace). (The story with [variable] is actually more complicated,
but we won't go into that.) Both [global] and [variable] have no
effect on variable names in any other proc. Consider the following
useless code (all procedures in this code are defined within the
global namespace):

set foo 1
set bar 2

proc useGlobalVars {} {
global foo bar
set foo 3
set bar 4
}

proc useNamespaceVars {} {
variable foo 5 bar 6
}

proc useQualifiedVars {} {
# "::" represents the global namespace
set ::foo 7
set ::bar 8
}

proc useLocalVars {} {
set foo 9
set bar 10
}

useGlobalVars; puts "useGlobalVars: $foo $bar"
useNamespaceVars; puts "useNamespaceVars: $foo $bar"
useQualifiedVars; puts "useQualifiedVars: $foo $bar"
useLocalVars; puts "useLocalVars: $foo $bar"

# (end of code) #

The output will look like this:

useGlobalVars: 3 4
useNamespaceVars: 5 6
useQualifiedVars: 7 8
useLocalVars: 7 8

In other words, in every procedure where you want access to a
namespace variable, you have to either use [global], [variable], or
qualified variable names; otherwise Tcl will treat variable names as
local, even if you've declared those same names global in another
procedure.

I hope that helps. If not, please do ask for clarification.

Aric