Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

variable problem (i might just be THICK ) 1

Status
Not open for further replies.

zskater

Programmer
Apr 14, 2001
22
GB
When the window for our drawing tool loads up it accesses our database
through C functions to find the names of the buttons and there
drop down menu names that we want displayed on the screen

###########################################################
proc pulldownmenu {} {

global celltype no_of_cells

set i 0
foreach celltype { Horse Pony Tack Corner Shelter Feed } {

menubutton .cells.mb$i -text $celltype -menu .cells.mb$i.menu -height 1 -width 8 -relief raised
set m [menu .cells.mb$i.menu -tearoff 0]

foreach no_of_cells { Small Medium Large ExtraLarge } {
$m add command -label $no_of_cells
-command {startCell $celltype $no_of_cells}
}

incr i 1

}

pack .cells.mb0 .cells.mb1 .cells.mb2 .cells.mb3 .cells.mb .cells.mb5 -padx 10 -pady 10 -side top -fill y

grid config .cells -column 1 -row 2 -columnspan 1 -rowspan 1 -sticky "snew"
}

pulldownmenu
###########################################################

The 'foreach no_of_cells ... ' part of the code is not like this in our final code but this is a simplified
version where no database info is needed.
Once the buttons have been created and displayed on screen , we need to be able to press a button
and for the procedure called 'startCell' to be called , as you can see in the pull down menu procedure
-command {startCell $celltype $no_of_cells}

The problem is that the buttons all get the variables $cellType and $no-of-cells set to the values they were last set
(eg. always feed and extra large) to and not the values of the variables at the time they were set



If you can understand my explanation , which was very difficult to put into words,
can you suggest a way to make this work as I dont have a clue ?


THANKS LOTS
STEVE
 
The quick summary:
[ul][li]Quoting with {} prevents variable substitution (and all other substitutions) when the command is parsed and executed.[/li] [li]Quoting with "" allows variable substitution (and all other substitutions) when the command is parsed and executed.[/li][/ul]
In simple cases, it's obvious:

[tt]% [ignore]set x 42[/ignore]
42
% [ignore]puts {"x" is $x\nThe current directory is [pwd]}[/ignore]
"x" is $x\nThe current directory is [pwd]
% [ignore]puts "\"x\" is $x\nThe current directory is [pwd]"[/ignore]
"x" is 42
The current directory is D:/tcltk[/tt]

The complications arise when you're registering chunks of Tcl code to be evaluated at a later point in time (which are often referred to as callbacks). This is what's happening with your -command arguments: you're giving Tcl some code to execute when the corresponding menu item is selected.

What happens is that when the Tcl interpreter parses the command creating the menu item, it's subject to standard substitution rules. In this case, you've quoted the -command argument in {}, so Tcl can't perform substitutions on that argument. The code is stored away verbatim, associated with the menu item.

Then, when the user selects the menu item, the chunk of code is retrieved and parsed once again according to the standard Tcl rules. Because the {} characters were stripped off in the previous round of parsing (quoting characters aren't part of the argument; they're used only for the purposes of grouping), Tcl can now substitute the values of the variables. But in this case, it's the value of celltype and no_of_cells when the menu item is selected, not when the item was created -- in other words, the last values assigned to these variables.

Assuming that no whitespace characters or other special Tcl characters like {, ", or \ appear in the value of your variables, you can get by with using "" to quote your -command argument instead of {}:

[tt]$m add command -label $no_of_cells -command "startCell $celltype $no_of_cells"[/tt]

If there's any possibility of one of those characters appearing in your variable values, though, you can't use "" to quote, because whitespace characters would break apart some of your arguments, and other special characters would cause parsing problems when your callback is executed. For example:

[tt]#whitespace in variable value
startCell black background 3
#special character in variable value
startCell aBad{situation 1[/b][/tt]

In these cases, you need to use the Tcl list command to create your callback. list builds a well-formed Tcl list of its arguments, and a Tcl command is just an instance of a Tcl list in which the first element in the command name, and all subsequent elements are command arguments. Thus, the safest approach is:

[tt]$m add command -label $no_of_cells -command [ignore][list startCell $celltype $no_of_cells][/ignore][/tt]

(By the way, the bodies of control statements like if and while seem to be exceptions. But in Tcl, control statements are Tcl commands, not keywords. You don't want substitutions to occur when the command is parsed initially, but if the condition is True in the case of an if statement, or each time through the loop in the case of a loop like while. So, you quote the body of the control statement with {} to prevent premature substitutions, and then the commands take care of passing the body to the Tcl interpreter for parsing and execution when appropriate.) - Ken Jones, President
Avia Training and Consulting
866-TCL-HELP (866-825-4357) US Toll free
415-643-8692 Voice
415-643-8697 Fax
 
I have tried the different ways you have suggested but the final value of the variable is still what i am getting

I tried
-command "startCell $celltype $no_of_cells"
-command startCell "$celltype $no_of_cells"
-command {startCell "$celltype $no_of_cells"}
-command {startCell "$celltype" "$no_of_cells"}
-command [list startCell $celltype $no_of_cells]

any other suggestions ?

Cheers
Steve
 
Logically:
-command [startCell $celltype $no_of_cells]
or:
-command [list [startCell $celltype $no_of_cells]]
 
startcell is a procedure

So when i use

-command [startCell $celltype $no_of_cells]
or:
-command [list [startCell $celltype $no_of_cells]]

i get an error: invalid command name startCell

So i need to do it some other way
 
when a button is pressed it must remember what the 2 variables were at the time they were created
 
I took the code sample you posted, and made the modification I suggested. It worked correctly (after defining a dummy startCell procedure which simply printed the arguments passed to it).

A theory... I noticed the global command at the top of your pulldownmenu procedure. I could see no reason to declare those variables as global based on what appeared in the procedure. In fact, you used both of those variables as index variables of foreach commands, which usually indicates that the variables hold transitory information. After each loop terminates, the index variable will retain the last value assigned to it. It strikes me as odd that you would need this information elsewhere in your application, and thus unlikely that you really need to declare the variables as global. And I suspect that somewhere else in your code, you might be trying to access those global variables again, rather than using the values passed as arguments to your startCell procedure. - Ken Jones, President
Avia Training and Consulting
866-TCL-HELP (866-825-4357) US Toll free
415-643-8692 Voice
415-643-8697 Fax
 
Could you please post your code so I could study it and work out what I am doing wrong


Thanks
Steve
 
Its ok I got it working now
Thanks very much for your help

perfect advice again !!!

Cheers
Steve
 
Here's the complete listing of the test file I used:

Code:
###########################################################

# Create a frame so that I can use the code posted verbatim

frame .cells

# Create a dummy startCell procedure that simply echoes
# out its arguments

proc startCell {type num} {
    puts "Type: $type\nNumber: $num"
}

# Here starts the original code as posted, with slight
# reformatting for posting online.
# Substantive changes are noted.

proc pulldownmenu {} {

    # Comment out unneeded global declaration
    # global celltype no_of_cells

    set i 0
    foreach celltype {Horse Pony Tack Corner Shelter Feed} {

        menubutton .cells.mb$i -text $celltype             -menu .cells.mb$i.menu             -height 1 -width 8 -relief raised

        set m [menu .cells.mb$i.menu -tearoff 0]

        foreach no_of_cells {Small Medium Large ExtraLarge} {
            
            # Use list command to quote the callback
            # Also added missing "\" at the end of the first line
            
            $m add command -label $no_of_cells                -command [list startCell $celltype $no_of_cells]
        }

        incr i 1

    }

    # Fix typo in packing .cells.mb4

    pack .cells.mb0 .cells.mb1 .cells.mb2 .cells.mb3 .cells.mb4          .cells.mb5  -padx 10 -pady 10 -side top -fill y
        
    grid config .cells -column 1 -row 2             -columnspan 1 -rowspan 1 -sticky "snew"
}

pulldownmenu

# Force display of the wish console on Windows and Macintosh
# so that I can see the output of my puts commands.

if {$tcl_platform(platform) != "unix"} {
    console show
}
###########################################################
- Ken Jones, President
Avia Training and Consulting
866-TCL-HELP (866-825-4357) US Toll free
415-643-8692 Voice
415-643-8697 Fax
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top