Home > Archive > Tcl > March 2006 > TK: question about "-command" usage with "{}" and double quoter
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
| Author |
TK: question about "-command" usage with "{}" and double quoter
|
|
|
| Hi,
I have some codes listed below:
entry $entry1 -width 20 -relief sunken -textvariable entry1
entry $entry2 -width 50 -relief sunken -textvariable entry2
button $confirm -text Confirm -command {
set commit [proc_to_run_other_thing $entry1 $entry2];
puts "entry1:$entry1, entry2:$entry2" }
button $w.command.cancel -text Cancel -command { set commit 0 }
pack ......
vwait commit
I found the proc_to_run_other_thing proc cannot use updated value for
entry1 and entry2, that's because I'm using "{}" to specify command,
then I think I should use double quoter . but I already have the puts
command which is using double quoter, so I cannot use double quoter for
the two command again.
How to solve the problem? Thanks.
| |
|
| Command callbacks are evaluated in global context
so {set commit 0} will concern global variable commit.
try
global commit
vwait commit
or even better
vwait ::commit
perhaps own namespace or OO-Tcl to avoid some unexpected side effects
in global context
See implemtation of Tk dialog for good example
in file dialog.tcl
| |
| Ralf Fassel 2006-03-28, 7:03 pm |
| * "Hans" <hansyin@gmail.com>
| I found the proc_to_run_other_thing proc cannot use updated value for
| entry1 and entry2, that's because I'm using "{}" to specify command,
| then I think I should use double quoter . but I already have the puts
| command which is using double quoter, so I cannot use double quoter for
| the two command again.
|
| How to solve the problem? Thanks.
- use a helper proc if -command gets lengthy
- use list to build up the command
proc button_helper {e1 e2} {
set ::commit [proc_to_run_other_thing $e1 $e2]
puts "entry1:$e1, entry2:$e"
}
button $confirm -text Confirm \
-command [list button_helper $entry1 $entry2]
See also
http://wiki.tcl.tk/9330
HTH
R'
| |
| Bryan Oakley 2006-03-28, 7:03 pm |
| Ralf Fassel wrote:
> * "Hans" <hansyin@gmail.com>
> | I found the proc_to_run_other_thing proc cannot use updated value for
> | entry1 and entry2, that's because I'm using "{}" to specify command,
> | then I think I should use double quoter . but I already have the puts
> | command which is using double quoter, so I cannot use double quoter for
> | the two command again.
> |
> | How to solve the problem? Thanks.
>
> - use a helper proc if -command gets lengthy
> - use list to build up the command
Excellent advice. Personally, I define "lengthy" as "more than one
command". It almost always makes all quoting problems vanish WRT
-command and for bindings.
| |
|
| Thanks a lot.
I'm sorry for I made a mistake in my code example, it should be:
entry $entry1_name -width 20 -relief sunken -textvariable
entry1_variable
entry $entry2_name -width 50 -relief sunken -textvariable
entry2_variable
button $confirm -text Confirm -command {
set commit [proc_to_run_other_thing $entry1_variable
$entry2_variable];
puts "entry1:$entry1_variable,
entry2:$entry2_variable" }
button $w.command.cancel -text Cancel -command { set commit 0
}
your code definitly works, thanks again. Can I have two more questions?
1. Is there a way to not use global variable in -textvariable for
entry? I just want to use the variable to get some inputing value from
user, then do sth in another proc(send those updated value to SQL
database). I don't like create too many global variables
2. I hope pass the updated variable value to my proc_to_run_other_thing
directly by "-command" in one line, can I do it? I don't like to create
too many procedures.
Thanks again.
| |
| Bryan Oakley 2006-03-29, 8:02 am |
| Hans wrote:
> Thanks a lot.
> 1. Is there a way to not use global variable in -textvariable for
> entry? I just want to use the variable to get some inputing value from
> user, then do sth in another proc(send those updated value to SQL
> database). I don't like create too many global variables
As my example showed, you don't need to use -textvariable at all. If you
do, it must represent a variable accessible from the global scope. That
means either a global variable or a fully qualified namespace variable.
There is no way to have it use a local variable.
> 2. I hope pass the updated variable value to my proc_to_run_other_thing
> directly by "-command" in one line, can I do it? I don't like to create
> too many procedures.
Why don't you like to "create too many procedures"? Procedures are a
tool to get your job done, and in this case will make your job easier.
However, you can certainly do what you want without using a proc. It
requires all quoting tricks that will make your code hard to read and
hard to maintain.
Here's how to do it. It is untested, but I think I got it right. That's
the problem with this approach however: it's _really_ hard to know just
by looking at it if it's correct or not, and it's difficult to modify
the code later:
button $confirm -text Confirm -command "
set commit \[proc_to_run_other_thing \$entry1_variable \
\$entry2_variable\];
puts \"entry1:\$entry1_variable, entry2:\$entry2_variable\""
This will, BTW, set the global variable "commit". Commands, like
bindings, execute in the global level.
If I were reviewing that code for use in a production environment I
would reject it.
| |
| Donal K. Fellows 2006-03-29, 8:02 am |
| Bryan Oakley wrote:
> However, you can certainly do what you want without using a proc. It
> requires all quoting tricks that will make your code hard to read and
> hard to maintain.
[...]
> button $confirm -text Confirm -command "
> set commit \[proc_to_run_other_thing \$entry1_variable \
> \$entry2_variable\];
> puts \"entry1:\$entry1_variable, entry2:\$entry2_variable\""
It strikes me that now is the time to point out that Tcl 8.5a4 has a new
trick up its sleeve that will allow a bridge between these two ways of
operating: the [apply] command, as described in TIP#194:
button $confirm -text Confirm -command [list apply {{x} {
global entry1_variable entry2_variable
set commit [proc_to_blah $entry1_variable $entry2_variable]
puts "entry1:$entry1_variable, entry2:$entry2_variable"
puts "Gratuitously, x = $x"
}} "gratuitous extra argument"]
At the moment, I suspect that using a helper procedure will continue to
be clearer, but the "too many procs" argument will be moot... :-)
Donal.
| |
|
| Thanks. Just as you suggedsted, I tried to use helper-proc and delete
-textvariables, it works. then I got another problem, I hope to return
a value(commit) from my proc , can I do it? I tried:
-command [set commit [list proc $entry1 $entry2]]
-command [set commit [[list proc $entry1 $entry2]]]
both do not work. Thanks .
another little question, Can I set a default value for my entry? before
, I used a textvariable, then I can set the default value by the
variable, now, I don't use textvariable any more. Is there another way
to set a default value for entry widget?
thanks.
| |
| Ralf Fassel 2006-03-30, 4:02 am |
| * "Hans" <hansyin@gmail.com>
| 1. Is there a way to not use global variable in -textvariable for
| entry? I just want to use the variable to get some inputing value
| from user, then do sth in another proc(send those updated value to
| SQL database). I don't like create too many global variables
As others have pointed out, a -textvariable is always global (or
namespace-global).
| 2. I hope pass the updated variable value to my proc_to_run_other_thing
| directly by "-command" in one line, can I do it?
Not reliably and directly. If you use quoting tricks some weird
contents of the entry *will* break the command.
So here's how to do it:
- using no -textvariable:
as Bryan has already shown in another post, you have to pass the
name of the entries to your proc and use the entry 'get' command to
get the contents:
set entry1 .e1
set entry2 .e2
set confirm .confirm
entry $entry1
entry $entry2
button $confirm -text Confirm \
-command [list proc_to_run_other_thing $entry1 $entry2]
proc proc_to_run_other_thing {entry1 entry2} {
# get the current contents of the entries
set contents1 [$entry1 get]
set contents2 [$entry2 get]
# now we can use $contents1 and $contents2
puts "entry1 has: $contents1"
puts "entry2 has: $contents2"
...
# set the global indicator _here_
set ::commit ...
}
Without a textvariable, you can set initial contents for the
entries via
$entry1 insert 0 "some initial text"
- using -textvariable:
you can pass the *name* of the variable to your proc and then use
'upvar' to look at the variable contents
set entry1 .e1
set entry2 .e2
set confirm .confirm
entry $entry1 -textvariable entry1_variable
entry $entry2 -textvariable entry2_variable
button $confirm -text Confirm \
-command [list proc_to_run_other_thing entry1_variable entry2_variable]
proc proc_to_run_other_thing {varname1 varname2} {
# get the current contents of the variables via upvar
upvar \#0 $varname1 contents1
upvar \#0 $varname2 contents2
# now we can use $contents1 and $contents2
puts "entry1 has: $contents1"
puts "entry2 has: $contents2"
...
# set the global indicator _here_
set ::commit ...
}
With a textvariable, you can set initial contents for the
entries either as above or by setting the textvariable:
set ::entry1_variable "some initial text"
HTH
R'
|
|
|
|
|