Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

How to get bind return?

22 views
Skip to first unread message

Huey

unread,
Jan 4, 2007, 12:32:37 PM1/4/07
to
Hi All,

My bind behaved ugly! What I need is to get the return of bind. My
code:

entest.tcl
proc get_entry {} {
global iWant

entry .ent -width 20 -textvariable e
pack .ent
bind .ent <Key-Return> {
set iWant [.ent get]
}
return $iWant
}
get_entry


When I ran this code by "source entest.tcl", and typed something into
.ent, I got nothing. But, when I re-ran this code by "source
entest.tcl", the input into .ent at the last time showed up! I am lost!

bind .ent <Key-Return> {
set iWant [.ent get]
}

behaved as a local namespace, the variable iWant is not accessible
beyond the { }. Therefore, there is a dilema:

1) if iWant is a local variable, it is not accessible; so the proc
can't get the return value from bind.
2) if iWant is a global variable, it will be accessible in its next
life!

Can somebody help me to get this iWant in robust? Thank you very much!

Huey

Bryan Oakley

unread,
Jan 4, 2007, 12:49:51 PM1/4/07
to
Huey wrote:
> Hi All,
>
> My bind behaved ugly! What I need is to get the return of bind. My
> code:
>
> entest.tcl
> proc get_entry {} {
> global iWant
>
> entry .ent -width 20 -textvariable e
> pack .ent
> bind .ent <Key-Return> {
> set iWant [.ent get]
> }
> return $iWant
> }
> get_entry
>

You seem to have a misunderstanding of how events work. When you do the
"bind" command above, it isn't going to wait for user input. It will set
the binding and then continue. Your procedure will return before the
user ever gets the chance to enter any data.

Then, when the user presses return in the entry, all it will do is set
the global variable iWant to whatever is in the widget.

The immediate solution to your problem is to have your proc get_entry
wait until the variable iWant changes before returning. You can do this
with vwait:

proc get_entry {} {
global iWant
entry .ent -width 20 -textvariable e
pack .ent
bind .ent <Key-Return> {
set iWant [.ent get]
}

vwait iWant
return $iWant
}

I wouldn't normally recommend doing it that way though. Do you really
intend for your whole application to pause until the user enters some
data? Or is it good enough that your application continues to work as
before, but when the user presses return something special will happen?

BTW: are you aware that you can associate a variable with the entry, so
you don't have to do "set iWant [.ent get]"? It's really quite handy. A
common pattern is something like this:

entry .ent -textvariable foo
bind .ent <Return> {doSomething}
proc doSomething {} {
global foo
puts "you entered: $foo"
}

Another common technique, useful to use the same routine for many
entries, is to *not* use -textvariable, but rather pass in the name of
the widget:

entry .ent
bind .ent <Return> [list doSomething .ent]
entry .ent2
bind .ent2 <Return> [list doSomething .end2]
proc doSomething {widget} {
puts "you entered: [$widget get]
}

Uwe Klein

unread,
Jan 4, 2007, 12:47:47 PM1/4/07
to
Huey wrote:
> Hi All,
>
> My bind behaved ugly! What I need is to get the return of bind. My
> code:
>
> entest.tcl
> proc get_entry {} {
> global iWant
>
> entry .ent -width 20 -textvariable e
> pack .ent
> bind .ent <Key-Return> {
> set iWant [.ent get]
> }
# The call to bind will set up (asynchronous) event handling for <Return> in .ent
# and then return ( with nothing, read the man page on bind ).

> return $iWant
# Then [get_entry] returns with an error because.
# at that moment in time nothing has happened. the variable "iWant"
# does not yet exist.
> }
> get_entry
# follow this with
vwait iWant
# vwait will wait until the variable iWant is changed ( i.e created or written to )

uwe

Huey

unread,
Jan 4, 2007, 11:06:01 PM1/4/07
to
Hi Bryan,

Thank you for your help. Your way of setting vwait works on single
entry. However, I can't get multiple entry widgets working. By the way,
I do need to wait for user input, then to get the typed in strings. If
I tried to do:

bind .ent-1 <Return> doSomething
bind .ent-2 <Return> doSomething

I can't get inputs on both ent-1 and ent-2, but got eight one.

I also tried your demo:


entry .ent
bind .ent <Return> [list doSomething .ent]
entry .ent2
bind .ent2 <Return> [list doSomething .end2]
proc doSomething {widget} {
puts "you entered: [$widget get]
}

I got the input on ent2 only. It seems that I might need to do this by
using bindtags command, but I can't figure out a correct syntaxt on it.
Anybody can help?

Hueuy

Gerald W. Lester

unread,
Jan 5, 2007, 12:38:54 AM1/5/07
to
Programming a GUI is different than programming a command line program.

In a command line program, you prompt the user for information, receive the
information and validate it, prompt for the next piece of information,
receive and validate it, etc... and when you have all of your info you
process it.

In a GUI driven program, you place all of the prompts on the screen and
allow the user to fill in all of the information then tell you they are done
by clicking on a button, then you validate all of their input and process it.

You can of course also do field by field validation as they enter data.

In short you need to stop attempting to have the program drive the user and
have the user drive the program. This is true regardless of what language
you write the GUI in.


--
+--------------------------------+---------------------------------------+
| Gerald W. Lester |
|"The man who fights for his ideals is the man who is alive." - Cervantes|
+------------------------------------------------------------------------+

Donal K. Fellows

unread,
Jan 5, 2007, 8:13:23 AM1/5/07
to
Gerald W. Lester wrote:
> In a GUI driven program, you place all of the prompts on the screen and
> allow the user to fill in all of the information then tell you they are done
> by clicking on a button, then you validate all of their input and process it.
>
> You can of course also do field by field validation as they enter data.

Much experience by *thousands* of GUI developers over many years
indicates that it is a Really Good Idea to use field-by-field
validation as a way of providing hints on whether a field is valid, but
not as a strictly enforced thing. This is because fields can be
transiently invalid for good reasons (sometimes to do with the way
users use the field, othertimes due to the way GUIs work). Save the
real enforcement for when that Submit/OK/Apply button is pressed.

Donal (not that I need to tell Gerald this, but people who haven't done
GUI design before tend to run into trouble with this point before
coming up with the above Pattern).

Bryan Oakley

unread,
Jan 5, 2007, 10:01:20 AM1/5/07
to
Huey wrote:
> Hi Bryan,
>
> Thank you for your help. Your way of setting vwait works on single
> entry. However, I can't get multiple entry widgets working. By the way,
> I do need to wait for user input, then to get the typed in strings. If
> I tried to do:
>
> bind .ent-1 <Return> doSomething
> bind .ent-2 <Return> doSomething
>
> I can't get inputs on both ent-1 and ent-2, but got eight one.
>
> I also tried your demo:
> entry .ent
> bind .ent <Return> [list doSomething .ent]
> entry .ent2
> bind .ent2 <Return> [list doSomething .end2]
> proc doSomething {widget} {
> puts "you entered: [$widget get]
> }
> I got the input on ent2 only. It seems that I might need to do this by
> using bindtags command, but I can't figure out a correct syntaxt on it.
> Anybody can help?
>

bindtags has absolutely nothing to do with it. Nothing at all. If you're
struggling with using normal bindings, bindtags will only confuse you more.

If you must display several entry fields and wait for them all to be
filled out, the generally accepted way is to create a dialog and only do
the processing when the user presses an "OK" button. Will that work for you?

For sure, you definitely do *not* want to have a vwait for each entry
field.

In such a case, you don't have to worry about bindings at all. Or, as is
sometimes done, you can bind <Return> to do the same thing as the OK button.

The real solution depends on the actual problem you are trying to solve,
and how that problem is integrated with the rest of your application.
For example, if you can't use a dialog we need to know why, and need to
know if there are other widgets that can or cannot be used at the same
time, etc. Also, we need to know what you really intend to do in your
<Return> bindings. Are you validating input, or are you kicking off a
long computation of some sort?

You're asking coding questions, but the real problem is you don't seem
to understand how to create a GUI in the first place, from a conceptual
point of view. We can help with that if you can give us a better idea of
what your application should look like.

Most likely the solution involves coding up a dialog box with an OK
button, so maybe the best next step is for you to tell us if that is an
acceptable solution or not.

Bryan Oakley

unread,
Jan 5, 2007, 10:03:12 AM1/5/07
to
Gerald W. Lester wrote:

> In short you need to stop attempting to have the program drive the user
> and have the user drive the program. This is true regardless of what
> language you write the GUI in.

I wish I had written that. Well put, Gerald.

0 new messages