For Programmers: Free Programming Magazines  


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
Hans

2006-03-28, 4:06 am

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.

Artur

2006-03-28, 4:06 am

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.
Hans

2006-03-29, 4:08 am

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.
Hans

2006-03-30, 4:02 am

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'
Sponsored Links







Also available: Server administration forum archive | Web Design forum archive | Software forum archive | Hardware reviews archive

Copyright 2008 codecomments.com