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

tk widget

75 views
Skip to first unread message

krith...@yahoo.com

unread,
Jan 4, 2006, 9:19:55 PM1/4/06
to
Hello
I am trying to get the data I enter on a field created in TK and pass
it to procedure. How do I do this in TK?

focus .editFr1.edit1 ;# put the cursor and focus to the first edit box
focus -force . ;# force focus back to the main window of the GUI
bind .editFr1.edit1 <Return> {set retKey 0; validate_sys_part(data)};
-- here I need to pass the data entered in the field. How do I
accomplish this?

Thanks
krithiga

Quokka

unread,
Jan 4, 2006, 9:55:43 PM1/4/06
to

You seem to be doing lots of unnecessary stuff in your example
focus / binding should not normally be necessary for simple gui
stuff, the window manager and Tk will take care of it for you.


The first way is the entry get command

e.g.
entry .edit
pack .edit

.edit get

Another way is to use a text variable:
(this only trick is that the text variable MUST
be a variable with global scope, i.e. a global)

e.g.

entry .edit1 -textvariable ::edit1_value
pack .edit1

Now whatever you enter in the .edit1 is automatically stored into
::edit1_value

If you want to perform validation on the user entered data,
(which your example seems to indicate).
then the entry provides a -vcmd option to do this for you.

See http://wiki.tcl.tk/768 for more information and examples

regards

Paul

Bryan Oakley

unread,
Jan 4, 2006, 10:23:32 PM1/4/06
to

Using a global variable:

entry .editFr1.edit1 -textvariable whatever
bind .editFr1.edit1 <Return> validate_sys_part
....
proc validate_sys_part {} {
global whatever
if {$whatever == ...} {
....
}
}

Avoiding the use of global variables:

entry .e
bind .e <Return> [list validate_sys_part .e]
....
proc validate_sys_part {widget} {
set whatever [$widget get]
if {$whatever == ...} {
....
}
}

Start with that, and let us know how it works for you. There are other
ways to accomplish similar goals but those are the two most
straight-forward.

I have no idea what you were trying to accomplish with retKey so I left
that out of the examples.

krith...@yahoo.com

unread,
Jan 5, 2006, 2:42:34 PM1/5/06
to
Hello
Thanks for your responses. I am also trying to pass the variable to a
procedure that has an arguemnt that expects this variable
entry .editFr1.edit1 -textvariable dat
bind .editFr1.edit1 <Return> validate_sys_part (dat)

proc validate_sys_part {data} {
global dat sys_part a field_name PRODMOD1 PRODMOD2

puts $dat
set RPC [read_product_config]
validate_entry (data,sys_part)
if {[validate_entry (data,sys_part)] == 1 } {
return -code error

}
set modelNum [string range data 5 end]
set model_name $PRODMOD1($modelNum)
set prod_type $PRODMOD2($modelNum)
set prod_status $PRODMOD($modelNum)
regexp (.*)- $model_name match MN1
set prod_code $PRODCODE($MN1)

if {[$PRODMOD($modelNum) ! = modelNum]} {
#beep
tk_messageBox -title "Invalid System part Number:model #nnnn not
found"
return -code -error
}


set CurrentItem [list sys_part modelNum model_name prod_type
prod_status prod_code]
return 0
}

In this proc I call another proc that this data I entered stored in
variable is passed to proc validate_entry where I pass the data and
sys_part. Though I declare these as global variables data is seen in
the proc validate_sys_part but not in validate_entry.

the proc validate entry is proc validate_entry {data,field_name} {

}

In this procedure I pass the field_name as sys_part from validate_entry
proc but it gives an error "cannot read variable name field_name".
Please let me know how we can do this

Thanks
krithiga

Bryan Oakley

unread,
Jan 5, 2006, 3:18:23 PM1/5/06
to
krith...@yahoo.com wrote:
> Hello
> Thanks for your responses. I am also trying to pass the variable to a
> procedure that has an arguemnt that expects this variable
> entry .editFr1.edit1 -textvariable dat
> bind .editFr1.edit1 <Return> validate_sys_part (dat)

This code is passing the literal string "(dat)" (without the quotes) to
the procedure validate_sys_part.

Tcl and Tk don't use parenthesis for function calls; looking through
your code it appears you think it does. Did you get that impression from
some documentation or a book? If so, let us know and we can help you
contact the author to correct that information.

If you want to call a procedure with the value stored in a variable
named "dat", you must pass it like so:

validate_sys_part $dat

Back to your original question. You apparently have a proc named
validate_sys_part that requires a value to be passed in to it. You also
have an entry field that the user can use to specify that value. To hook
the two together you'll need an intermediate procedure since you can't
change the API of validate_sys_part. No harm; procs are very cheap.

entry .editFr1.edit1 -textvariable dat
bind .editFr1.edit1 <Return> validate_input
proc validate_input {} {
global dat
validate_sys_part $dat
}

There are more general ways to solve the same problem, but lets stick
with that until you get it working for this particular case.

>
> proc validate_sys_part {data} {
> global dat sys_part a field_name PRODMOD1 PRODMOD2
>
> puts $dat
> set RPC [read_product_config]
> validate_entry (data,sys_part)
> if {[validate_entry (data,sys_part)] == 1 } {

I'm not sure why you are calling validate_entry more than once. As
mentioned before, this passes the literal string "(data,sys_part)"
(without the quotes) to the procedure validate_entry. You probably need
something like:

if {[validate_entry $data $sys_part] == 1} {...}

> return -code error
>
> }
> set modelNum [string range data 5 end]

Again, that needs to be $data

> set model_name $PRODMOD1($modelNum)
> set prod_type $PRODMOD2($modelNum)
> set prod_status $PRODMOD($modelNum)
> regexp (.*)- $model_name match MN1

It's generally a good idea to get in the habit of putting your
expressions in curly braces:

regexp {(.*)-} $model_name match MN1

> set prod_code $PRODCODE($MN1)
>
> if {[$PRODMOD($modelNum) ! = modelNum]}

The extra []'s in the above statment causes Tcl to look for a procedure
name that is stored in the variable $PRODMOD($modelNum). That is almost
certainly not what you want. Also, because modelNum has no preceeding $,
you are comparing to the literal string "modelNum" (again, without the
quotes).

Probably what you meant was:

if {$PRODMOD($modelNum) != $modelNum} {...}

{
> #beep
> tk_messageBox -title "Invalid System part Number:model #nnnn not
> found"
> return -code -error
> }
>
>
> set CurrentItem [list sys_part modelNum model_name prod_type
> prod_status prod_code]

The above creates a list with the literal strings "sys_part",
"modelNum", etc. You need dollar signs if you want the values of the
variables.

You seem to think that Tcl is some other language. In Tcl, function
calls do not use parenthesis, and to dereference a variable name you
need a preceeding dollar sign (there are other ways to dereference a
variable but I don't want to confuse matters even more for you...)

krith...@yahoo.com

unread,
Jan 5, 2006, 3:44:40 PM1/5/06
to
Hi
Thanks. I did change my proc before I saw this to use $dat to
reference. So what data is entered is passed to the procedure
validate_sys_part . But when I call

validate_entry($data,$sys_part) -


proc validate_entry {data2,field_name} {
global data2 dat field_name lookup DX2 sys_part data
puts "I am in validate_entry"
puts "Data is $data2"
puts data2
puts $field_name
}
In this proc it gives an Error cannot read data2 . How do I pass this
value $data from validate_sys_part to validate_entry. I used the $
sign.
So may be as you suggested I do validate_entry before I call
validate_sys_part. I can try this. The reason I was calling
validate_entry twice is to check if it returned an error. The first
time it is called to perform the procedure and then checked if it
returned an error.
This data is not passed to the proc validate_entry.

Thanks
krithiga

Bryan Oakley

unread,
Jan 5, 2006, 4:29:46 PM1/5/06
to
krith...@yahoo.com wrote:
> Hi
> Thanks. I did change my proc before I saw this to use $dat to
> reference. So what data is entered is passed to the procedure
> validate_sys_part . But when I call
>
> validate_entry($data,$sys_part) -

That is not how you call procedures in Tcl. Tcl doesn't use parenthesis,
as I described in my last message. Nor does Tcl use commas. It needs to
be this:

validate_entry $data $sys_part

>
>
> proc validate_entry {data2,field_name} {

You cannot (*) use commas in a proc definition. It must be:

proc validate_entry {data2 field_name} {...}

You should re-read the Tcl man page [1] where it describes how tcl
breaks up commands into words, and the proc man page [2] where it talks
about formal arguments.

(*) You can use commas in a proc definition, it's just that they don't
work the way they do in many other languages. While learning Tcl
fundamentals it's easier to simply learn you can't use commas.

1: http://www.tcl.tk/man/tcl8.4/TclCmd/Tcl.htm
2: http://www.tcl.tk/man/tcl8.4/TclCmd/proc.htm

Gerald W. Lester

unread,
Jan 5, 2006, 4:38:26 PM1/5/06
to
krith...@yahoo.com wrote:
> Hello
> Thanks for your responses. I am also trying to pass the variable to a
> procedure that has an arguemnt that expects this variable
> entry .editFr1.edit1 -textvariable dat
> bind .editFr1.edit1 <Return> validate_sys_part (dat)

This is in correct syntax, do:
bind .editFr1.edit1 <Return> [list validate_sys_part dat]

>
> proc validate_sys_part {data} {
> global dat sys_part a field_name PRODMOD1 PRODMOD2
>
> puts $dat
> set RPC [read_product_config]
> validate_entry (data,sys_part)

This is not how we call procedures in Tcl, we do:
validate_entry data sys_part
or if you want the conents (which I think is what you want):
validate_entry $data $sys_part

> if {[validate_entry (data,sys_part)] == 1 } {
> return -code error
>
> }
> set modelNum [string range data 5 end]
> set model_name $PRODMOD1($modelNum)
> set prod_type $PRODMOD2($modelNum)
> set prod_status $PRODMOD($modelNum)
> regexp (.*)- $model_name match MN1
> set prod_code $PRODCODE($MN1)
>
> if {[$PRODMOD($modelNum) ! = modelNum]} {
> #beep
> tk_messageBox -title "Invalid System part Number:model #nnnn not
> found"
> return -code -error
> }
>
>
> set CurrentItem [list sys_part modelNum model_name prod_type
> prod_status prod_code]
> return 0
> }
>
> In this proc I call another proc that this data I entered stored in
> variable is passed to proc validate_entry where I pass the data and
> sys_part. Though I declare these as global variables data is seen in
> the proc validate_sys_part but not in validate_entry.
>
> the proc validate entry is proc validate_entry {data,field_name} {

This is not how you declare a procedure with two arguements in Tcl, we do:

proc validate_entry {data field_name} {

>
> }
>
> In this procedure I pass the field_name as sys_part from validate_entry
> proc but it gives an error "cannot read variable name field_name".
> Please let me know how we can do this

You need to learn Tcl syntax a little better and stop using C/Java syntax
when writing Tcl.

krith...@yahoo.com

unread,
Jan 5, 2006, 7:33:28 PM1/5/06
to
Hello
Thanks for your responses. They were helpful. When I was putting a
comma when calling the procedure it did nto give me a syntax so I used
it that way. I am reading the man pages and it seems straightforward to
set arrays. But when I use them I am ruuning into issues. I also have
to set an array with entries

set CurrentItem [list sys_part $modelNum $model_name $prod_type
$prod_status $prod_code]

I need each of these items in outside the procedure. I have defined
CurrentItem to be global but cannot get its items as each of them is a
variable . I have defined these as global. Do you have any suggestions?

Thanks
krithiga

Bryan Oakley

unread,
Jan 5, 2006, 8:57:48 PM1/5/06
to
krith...@yahoo.com wrote:
> Hello
> Thanks for your responses. They were helpful. When I was putting a
> comma when calling the procedure it did nto give me a syntax so I used
> it that way.

It's not a syntax error, which is why you didn't get a syntax error :-)

A string like foo,bar appears to Tcl as a single "word" of 7 bytes
rather than two "words" separated by a comma. As long as what you're
calling expects only a single word you won't get a runtime error.

So, calling a procedure with "foo,bar" isn't an error, it just doesn't
do what you naively expect.

> I am reading the man pages and it seems straightforward to
> set arrays. But when I use them I am ruuning into issues. I also have
> to set an array with entries

When you say "I also have to set an array with entries" do you mean "I
have a homework assignment and this is what I'm supposed to do"? It is
beginnign to sound suspiciously like a homework assignment.

While we're happy to help, we tend not to do people's homework for them.
This forum is for helping solve technical issues, not do your work for you.

If you're having issues with arrays, show us the exact code and the
exact error message and we can tell you what you're doing wrong.

>
> set CurrentItem [list sys_part $modelNum $model_name $prod_type
> $prod_status $prod_code]
>
> I need each of these items in outside the procedure. I have defined
> CurrentItem to be global but cannot get its items as each of them is a
> variable .

What you say doesn't make much sense. Once you set it, and define it as
global, it will be available wherever else you declare it as global.

CurrentItem will contain the data that is in the variables at the time
you set CurrentItem. Once you set CurrentItem, if you change a variable
it won't change CurrentItem.

For example:

set modelNum 12
set model_name "Nimbus 2000"
set prod_type "broom"
set prod_status "imaginary"
set prod_code "xyzzy"


set CurrentItem [list sys_part $modelNum $model_name $prod_type \
$prod_status $prod_code]

After doing the above, CurrentItem will be {sys_part 12 {Nimbus 2000}
broom imaginary xyzzy}. If it is declared global, it can be accessed
anywhere.

krith...@yahoo.com

unread,
Jan 5, 2006, 9:29:00 PM1/5/06
to
Hello
Well I have already set the array with entries and accessing it
outside the procedure has been an issue. Though I did this with a
procedure call.

proc valid_sys_part {data} {
.. code..here

set CurrentItem [list sys_part $modelNum $model_name $prod_type
$prod_status
$prod_code]

set MODNAME [lindex $CurrentItem 2]
set MODELNUM [lindex $CurrentItem 1]
All these varaibles in the array are computed in the above procedure
based on data passed. I used lindex to access all these variables.
Inside this procedure it is fine.

}

Outside the procedure I call MODNAME and MODELNUM and use it to do a
string compare it says
"Error can't read MODELNUM no such variable."
If I call parray CurrentItem outside the procedure - it says
CurrentItem is not an array though it is declared as global

When I use a procedure and pass these values in the array then I can
access it. Without using a procedure how do I access the array values
of CurrentItem.

I never meant for anyone to do my homework, I am new to TCL and hence I
am running into these issues.

Thanks
krithiga

Bryan Oakley

unread,
Jan 5, 2006, 11:08:39 PM1/5/06
to
krith...@yahoo.com wrote:
> Hello
> Well I have already set the array with entries and accessing it
> outside the procedure has been an issue. Though I did this with a
> procedure call.
>
> proc valid_sys_part {data} {
> .. code..here
>
> set CurrentItem [list sys_part $modelNum $model_name $prod_type
> $prod_status
> $prod_code]
> set MODNAME [lindex $CurrentItem 2]
> set MODELNUM [lindex $CurrentItem 1]
> All these varaibles in the array

What array? I don't see the use of an array in the above code.

> ...


> Outside the procedure I call MODNAME and MODELNUM and use it to do a
> string compare it says
> "Error can't read MODELNUM no such variable."

If you get that error it means either a) you typed the variable wrong,
or b) you didn't declare it global.

Show us the exact code and we can find the problem. Otherwise we have to
keep playing a guessing game.

> If I call parray CurrentItem outside the procedure - it says
> CurrentItem is not an array though it is declared as global

Based on your earlier code samples, CurrentItem is _not_ an array - it
is a list. Those are two separate data types.

This is an array:

set CurrentItem(a) "this is element a"
set CurrentItem(b) "this is element b"
parray CurrentItem

This is a list:

set CurrentItem [list "this is element a" "this is element b"]
puts $CurrentItem

I think you are confusing the two.

krith...@yahoo.com

unread,
Jan 6, 2006, 12:53:04 PM1/6/06
to
Hello
OK here is my code
global CurentItem1 MODNAME MODELNUM
proc validate_sys_part {data} {
global dat sys_part PRODMOD1 PRODMOD2 PRODMOD PRODCODE PRODMOD0
model_name prod_type prod_status prod_code modelNum
global MODNUM MODNAME PRODTYPE PRODSTAT PROD_CODE CurrentItem1
CurrentItem
set CurrentItem [list]
validate_entry $data sys_part
if {[validate_entry $data sys_part] == 1 } {
return -code error

}
set modelNum [string range $data 5 end]


set model_name $PRODMOD1($modelNum)
set prod_type $PRODMOD2($modelNum)
set prod_status $PRODMOD($modelNum)
regexp (.*)- $model_name match MN1
set prod_code $PRODCODE($MN1)

if {[string compare $PRODMOD0($modelNum) $modelNum]!= 0} {


#beep
tk_messageBox -title "Invalid System part Number:model #nnnn not
found"
return -code -error
}


# set CurrentItem [list sys_part $modelNum $model_name $prod_type
$prod_status $prod_code]

#lappend CurrentItem sys_part $modelNum $model_name $prod_type
$prod_status $prod_code
#puts $CurrentItem

set SP [lindex $CurrentItem 0]


set MODNAME [lindex $CurrentItem 2]
set MODELNUM [lindex $CurrentItem 1]

set PRODTYPE [lindex $CurrentItem 3]
set PRODSTAT [lindex $CurrentItem 4]
set PROD_CODE [lindex $CurrentItem 5]
set CurrentItem1($modelNum) $modelNum
parray CurrentItem1
puts $CurrentItem1($modelNum)

}

parray CurrentItem1

If I use it outside the proc it says CurrentItem1 is not an array

What I am trying to accomplish is set Current Item with the
entries(nodel_name, modelNum...) and access these entries outside the
procedure. Do not know if a list or an array is best to do this. I
declared a list and then used lindex to access each element. When I use
these outside the procedure(like MODNAME and MODELNUM) it gives Error
varaible not found. I do not have a key by which I access these. It is
like a lookup table. What am I doing wrong?

krith...@yahoo.com

unread,
Jan 6, 2006, 1:13:25 PM1/6/06
to
Hi
I forgot to add this at the top of my code
bind .editFr1.edit1 <Return> {validate_sys_part $dat}

Thanks
krithiga

Bryan Oakley

unread,
Jan 6, 2006, 1:53:28 PM1/6/06
to
krith...@yahoo.com wrote:
> Hello
> OK here is my code
> ...

> If I use it outside the proc it says CurrentItem1 is not an array

Nowhere in the code that you posted do you call validate_sys_part; until
that procedure is called CurrentItem1 isn't set to anything. If
CurrentItem1 has never been initialized, you'll get the error that you
are seeing.

Besides that one fundamental mistake, you have an error with this block
of code:

# tk_messageBox -title "Invalid System part Number:model #nnnn not
found"
> return -code -error

That needs to be "return -code error".

Also, in the preceeding statement you set the title to something really
large; typically the title is something like "Invalid part number", with
the longer text as part of the -message.

Bryan Oakley

unread,
Jan 6, 2006, 1:57:49 PM1/6/06
to

Even with that statement added to the code you posted earlier, you still
aren't calling validate_sys_part before calling parray at the end of the
script. The way you've designed your code, you must call
validate_sys_part to initialize CurrentItem1.

Here's a suggestion: add a button so you can do the parray after you've
tried entering some data and validating it:

pack [button .debug -text Debug -command debug]
proc debug {} {
global CurrentItem1
parray CurrentItem1
}

Now, type in some text, press return to do the validation, then click on
the button to see that CurrentItem1 does indeed have data in it

krith...@yahoo.com

unread,
Jan 6, 2006, 7:35:53 PM1/6/06
to
Well your example works. I used a proc to get CurrentItem1 otherwise it
is not seeing the value. I call Validate_sys_part only once. In my code
it cannot be called mor than once as I am calling it to validate
entries.
Based on my original question of capturing the data in a variable if
I do this for more fields the focus gets set on all fields instead of
second field.Here is the code
proc display_screen1 {} {
global lookup SCRDEF0 SCRDEF lookup0 dat sys_part DefaultScreen
if {[string compare $DefaultScreen startup] == 0} {

set SCR1 $SCRDEF0(startup)

} else {
set SCR1 $SCRDEF($DefaultScreen)
}

set SCR2 [lindex $SCR1 0 ]
set SCR3 [split $SCR2 , ]
foreach FN $SCR3 {

set FN [string trimleft $FN]
puts $FN
set FN1 [string trimleft [lindex $lookup0($FN) 0]]
frame .editFr$FN -borderwidth 10
pack .editFr$FN -side top -fill x
label .editFr$FN.label$FN -text $FN1: -padx 0 -font {ariel 14 bold}
entry .editFr$FN.edit$FN -width 30 -relief sunken -textvariable NOS
-font {ariel 14 bold}
pack .editFr$FN.label$FN -side left -anchor w
pack .editFr$FN.edit$FN -side right -anchor e
.editFr$FN.edit$FN configure -background lightgray
focus .editFr$FN.edit$FN
bind .editFr$FN.edit$FN <Return> {set retKey 0; validate_entry $NOS
$FN ; CurrItem}

#}

}

Now where I set NOS for textvariable and use this variable when I bind
is not working corrrectly. What happens is when I type on second field
on screen all fields are getting updated with the value. But I change
NOS to $FN it does not do that? Why does this happen?

Bryan Oakley

unread,
Jan 6, 2006, 11:42:45 PM1/6/06
to
krith...@yahoo.com wrote:
> Well your example works. I used a proc to get CurrentItem1 otherwise it
> is not seeing the value.

I don't understand that statement. There's no magic in it not seeing the
value. If a proc doesn't see a value it's because you are doing
something wrong, not because it can't be done.

> I call Validate_sys_part only once. In my code
> it cannot be called mor than once as I am calling it to validate
> entries.
> Based on my original question of capturing the data in a variable if
> I do this for more fields the focus gets set on all fields instead of
> second field.

What you say is incorrect, but perhaps it is just a case of using the
wrong terminology. Focus can only be on a single widget at any one time,
so you must mean something other than focus.

> Here is the code
> ...


> Now where I set NOS for textvariable and use this variable when I bind
> is not working corrrectly. What happens is when I type on second field
> on screen all fields are getting updated with the value. But I change
> NOS to $FN it does not do that? Why does this happen?

You are telling every entry widget to use the same textvariable when you
use NOS for every one. So, when you change the value in that
textvariable, it changes every widget associated with that variable.
What else would you expect it to do? When you use $FN, since $FN is
unique for each field they don't all change at the same time.

Now that you've shown us your real problem, might I suggest trying the
following, which involves using an array to store your data.

Put this code in a file, run it with wish, enter some data in each field
and press return. On stdout you'll see that it's correctly seeing the
proper values.

# beginning of the example code

proc display_screen {} {
variable data
set SCR3 {Test1 Test2 Test3}
foreach FN $SCR3 {
set FN1 "Field $FN"


frame .editFr$FN -borderwidth 10
pack .editFr$FN -side top -fill x
label .editFr$FN.label$FN -text $FN1: -padx 0 -font {ariel 14 bold}

# notice the use of an array for the textvariable


entry .editFr$FN.edit$FN -width 30 -relief sunken \

-textvariable data($FN) \


-font {ariel 14 bold}
pack .editFr$FN.label$FN -side left -anchor w
pack .editFr$FN.edit$FN -side right -anchor e
.editFr$FN.edit$FN configure -background lightgray

# this serves no real purpose since it's in a loop and only
# one widget can have focus at a time
# focus .editFr$FN.edit$FN
bind .editFr$FN.edit$FN <Return> [list validate_entry $FN]
}
set FN [lindex $SCR3 0]
set firstentry .editFr$FN.edit$FN
after idle [list focus $firstentry]
}

proc validate_entry {FN} {
variable data
puts "validating field $FN; value is '$data($FN)'"
}

display_screen

# end of the example code

By the way, instead of binding to <Return>, the text widget has some
options specfically for validating input. The main drawback to binding
on <Return> doesn't handle other cases such as when the user uses the
tab or shift-tab key to go to a different field, or clicks in another
field, etc.


Cameron Laird

unread,
Jan 7, 2006, 8:08:02 PM1/7/06
to
In article <1136514540....@z14g2000cwz.googlegroups.com>,
<krith...@yahoo.com> wrote:
.
.

.
>I never meant for anyone to do my homework, I am new to TCL and hence I
>am running into these issues.
.
.
.
<URL: http://wiki.tcl.tk/tutorial > might interest you.

krith...@yahoo.com

unread,
Jan 9, 2006, 2:25:30 PM1/9/06
to
hello
Thanks. For validate_entry the data and filed has to be passed. When
I use the list it says " invalid command name validate_sys_part
0206061234 sys_ser. So I took the list out

proc display_screen1 {} {
global lookup SCRDEF0 SCRDEF lookup0 dat sys_part DefaultScreen

address serial_num FN SNM


if {[string compare $DefaultScreen startup] == 0} {

set SCR1 $SCRDEF0(startup)

} else {
set SCR1 $SCRDEF($DefaultScreen)
}

set SCR2 [lindex $SCR1 0 ]
set SCR3 [split $SCR2 , ]
foreach FN $SCR3 {

puts $FN


set FN [string trimleft $FN]
puts $FN
set FN1 [string trimleft [lindex $lookup0($FN) 0]]

puts "FN1 is $FN1"


frame .editFr$FN -borderwidth 10
pack .editFr$FN -side top -fill x
label .editFr$FN.label$FN -text $FN1: -padx 0 -font {ariel 14 bold}

entry .editFr$FN.edit$FN -width 30 -textvariable address($FN) -relief
sunken -font {ariel 14 bold}


pack .editFr$FN.label$FN -side left -anchor w
pack .editFr$FN.edit$FN -side right -anchor e
.editFr$FN.edit$FN configure -background lightgray

bind .editFr$FN.edit$FN <Return> {set retKey 0;

set SNM $address($FN)
puts "SNM is $SNM"
validate_entry $SNM $FN
}

puts "I am here after foreach"
set FN [string trimleft [lindex $SCR3 0]]


set firstentry .editFr$FN.edit$FN
after idle [list focus $firstentry]
}

proc validate_entry {data field_name} {
global dat lookup DX2 sys_part DAT3 address serial_num FN SNM
puts $data
puts $field_name
set field_name [string trimleft $field_name]
set DX2 $lookup($field_name)
set data [string toupper $data]
regsub -all "\[ \t\n\]+" $data {} $data
set data [string trim $data]

if {[regexp DX2 $data] != 1} { # test data against correct format
#tk_messageBox -title "Electronic Traveler Entry Error" -type ok -icon
error \
set $data "" ;# clear the entry box text
#return 1 ;# invalid input
}

# return 0 ; OK
puts "I am done with valid entry"
}
I removed the list and the data is entered but is not progessing to the
next field as when I hit return Key it stays in the same field as it
executes the same thing. it does not come out of the foreach loop. I
put in the code for validate_entry. What am I missing?

Thanks
krithiga

Bryan Oakley

unread,
Jan 9, 2006, 3:08:55 PM1/9/06
to
krith...@yahoo.com wrote:
> hello
> Thanks. For validate_entry the data and filed has to be passed.

Why? Is this a requirement placed on you, or an assumption you are making?

> When
> I use the list it says " invalid command name validate_sys_part
> 0206061234 sys_ser. So I took the list out

Can you show the code you used before taking the list out, and also
after? Certainly the code I posted didn't have this error, so you're
doing something wrong in translating it to your code.

> ...


> bind .editFr$FN.edit$FN <Return> {set retKey 0;
>
> set SNM $address($FN)
> puts "SNM is $SNM"
> validate_entry $SNM $FN
> }
>

I strongly recommend you use a proc rather than a bunch of inline code.
There's simply no reason not to. procs are cheap.

bind .editFr$FN.edit$FN <Return> [list validate $FN]
proc validate {FN} {
global address retKey


set retKey 0
set SNM $address($FN)
puts "SNM is $SNM"
validate_entry $SNM $FN
}

> ...


> I removed the list and the data is entered but is not progessing to the
> next field as when I hit return Key it stays in the same field as it
> executes the same thing.

You do not tell it to progress to the next field. Generally speaking,
you need to know what window the cursor is in, then use something like
"focus [tk_focusNext $window]"

You can include the window parameter as part of the return binding:

bind .editFr$FN.edit$FN <Return> \
[list validate $FN .editFr$FN.edit$FN]
proc validate {FN w} {
if {[validate_entry ...]} {
focus [tk_focusNext $w]
}
}


> it does not come out of the foreach loop. I
> put in the code for validate_entry. What am I missing?

There is no foreach loop in the code that gets executed when you press
return, so I don't understand what you mean when you say "it does not

come out of the foreach loop".

There are other errors in your code. For one thing, you are missing a
curly brace. Your code looks like this:

proc display_screen1 {} {
...
proc validate_entry {data field_name} {
...
}

My guess is, you need a closing curly brace on the line before "proc
validate_entry". While it's possible to define a proc inside another
proc, it is unusual. Since you are just now learning Tcl it's best to
stick to the standard practices.

Also, this code has a bug:

proc validate_entry {data field_name} {
...


error \
set $data "" ;# clear the entry box text

That is wrong in at least two ways. For one, the error command doesn't
take tcl code to execute.

Second, data is a local variable that contains whatever is in
$address($FN). That is, what the user entered.

Let's assume for the moment that the user entered "bogus". When you do
'set $data ""' that is equivalent to 'set bogus ""' which has no effect
in your code.

Remember that the -textvariable for each entry is address($FN); data is
just a local variable that has the string passed in. Thus, to reset the
entry you need to do 'set address($field_name) ""'. I bet users will be
really surprised to see their input vanish if it's incorrect; you might
want to rethink that.

FWIW, your code would be a bit more easy to read if you were consistent
with variable names; if you use FN for field name in one place, you
should use FN as the field name in other places; it makes it easier to
mentally tie the sections of code together.

krith...@yahoo.com

unread,
Jan 12, 2006, 5:56:59 PM1/12/06
to
Hi
In my code here how do I set upon focus: not allow tab-forward until
the field is successfully completed?

Thanks
krithiga
Bryan Oakley wrote:

Bryan Oakley

unread,
Jan 12, 2006, 6:32:49 PM1/12/06
to
krith...@yahoo.com wrote:
> Hi
> In my code here how do I set upon focus: not allow tab-forward until
> the field is successfully completed?
>

Using the tab key to move between fields is controlled by class
bindings. To inhibit class bindings include a break in your widget
specific binding.

Here's an example:

bind $entryWidget <Tab> {if {![valid ...]} break}

You can't really prevent users from clicking in other fields though, so
this is likely going to give you a false sense of security. Of course,
when focus goes to another window you can always force it back to where
you want, but that is decidedly non-user-friendly.

Instead of forcing focus to a widget, I recommend simply letting the
user know if the field is valid or not so they can make the choice to
move focus or not. For example, if the field is invalid you can change
the color of the widget or the label.

krith...@yahoo.com

unread,
Jan 12, 2006, 8:45:46 PM1/12/06
to
Hi
When the user enters data and the data is invalid the focus has to be
on the current field. So break comes out of the loop but the focus gets
advanced to the next field. How can it be made to stay in the same
field to enter correct data?

Thanks
krithiga
Bryan Oakley wrote:

Bryan Oakley

unread,
Jan 12, 2006, 10:07:11 PM1/12/06
to
krith...@yahoo.com wrote:
> Hi
> When the user enters data and the data is invalid the focus has to be
> on the current field. So break comes out of the loop but the focus gets
> advanced to the next field. How can it be made to stay in the same
> field to enter correct data?

Exactly the way I said in my earlier reply. If you create a binding on
<Tab> for the widget, and that binding does a "break", the normal
behavior of <Tab> will be interrupted.

Try this experiment:

entry .e1
entry .e2
pack .e1 .e2
bind .e1 <Tab> {break}
bind .e2 <Tab> {break}

You should see that pressing <Tab> does not move you from one field to
the other.

krith...@yahoo.com

unread,
Jan 13, 2006, 1:26:58 PM1/13/06
to
Hi
Yes the experiment works but not my code! Here is the code I put with
break. it is going to the next field after it shows the error on screen
if I type incorrrect data

Thanks
krithiga

bind .editFr$FN.edit$FN <Return> [list validate $FN
.editFr$FN.edit$FN]

proc validate {FN w} {
global address retKey
set CurrentItem2 [list]


set retKey 0
set SNM $address($FN)
puts "SNM is $SNM"
validate_entry $SNM $FN

validate_special $SNM $FN
if {[validate_entry $SNM $FN] == 1 && [validate_special $SNM
$FN] == 1 } {
break

} else {

focus [tk_focusNext $w]

Bryan Oakley

unread,
Jan 13, 2006, 1:46:06 PM1/13/06
to
krith...@yahoo.com wrote:
> Hi
> Yes the experiment works but not my code! Here is the code I put with
> break. it is going to the next field after it shows the error on screen
> if I type incorrrect data

As I said in the earlier message, the break must be part of the bind,
not part of the procedure.

However, instead of doing that, in your validate code you can do "return
-code break" to get the same effect.

So, either do it this way:

bind $widget <Tab> {if {![validate]} break}

or:

bind $widget <Tab> {validate}
proc valid {} {
if {<data isn't valid>} {
return -code break
}
}

This is all documented in the bind and break man pages. I get the
impression you haven't read those yet; perhaps now would be a good time
to do that.

krith...@yahoo.com

unread,
Jan 13, 2006, 3:10:41 PM1/13/06
to
Hi
OK. I have 3 procedures I call after the return.In the below code I
am calling 2. If I put a list validate, then the data is getting
adavnced. I removed the list and had curly braces aorund and then when
there is an error it stays in same field. OK. But when there is no
error after the 3rd field when I press return , it is not going to the
next field! What I am I doing wrong?
So if I have a list it is adavncing to the next field but without list
it stays in same field after 3rd entry!

bind .editFr$FN.edit$FN <Return> [list validate $FN
.editFr$FN.edit$FN]

proc validate {FN w} {
global address retKey Errflag SNM

set retKey 0
set SNM $address($FN)
puts "SNM is $SNM"


validate_entry $SNM $FN
puts "Errflag in display_screen1 is $Errflag"
if {$Errflag == 1} {
puts "I am here because of error"
return -code break

}

focus [tk_focusNext $w]



}

Bryan Oakley

unread,
Jan 13, 2006, 4:02:22 PM1/13/06
to
krith...@yahoo.com wrote:
> Hi
> OK. I have 3 procedures I call after the return.In the below code I
> am calling 2. If I put a list validate, then the data is getting
> adavnced. I removed the list and had curly braces aorund and then when
> there is an error it stays in same field. OK. But when there is no
> error after the 3rd field when I press return , it is not going to the
> next field! What I am I doing wrong?

It seems that you aren't taking the time to understand the examples I've
given to see why they work. You are cutting and pasting code without
understanding, which is why you keep making the same type of mistakes
over and over.

For this specific problem, the problem is in your logic somewhere. Tk
has no defaults for moving focus on anything but <Tab> and <Shift-Tab>
and you are having problems with <Return>. What that means is, focus
will only move when you tell it to move. Thus, you have problems in your
logic where you are telling it to move at the wrong times.

The "return -code break" absolutely does nothing as part of the code
executed when the user presses <Return>. My example was specifically for
<Tab> because that's what I thought your earlier post was about.

The bottom line is, you haven't taken the time to understand some very
fundamental things about Tk -- things you need to know before doing
something of an intermediate level such as creating dynamic forms.

Lets look at a few basic pieces of information:

"return -code break" or adding ";break" to a binding means "don't
continue with evaluating binding scripts". If there are no other binding
scripts (such as the case with <Return>) it has no effect. This is
documented in the bind man page.

Focus changes are defined in the "all" bindtag for <Tab> and
<Shift-Tab>. "all" bindings fire after instance bindings. You can read
about this in the bindtags man page. This is why break works when you
put a binding on <Tab> -- if you do a break in your binding, it prevents
the "all" binding from being executed and focus therefore doesn't change.

If you put curly braces around a script attached to a binding, variable
substitution happens when the binding fires. When you use [list ...],
substitution happens when the binding is defined. As a general rule you
almost always want to use list. In your specific case, you want to use list.

Thus, if you do this:

bind ... <Return> [list validate $FN .editFr$FN.edit$FN]

Then the procedure validate will get passed whatever FN was at the time
the bind command was run. Since you are calling this in a loop and want
the field name associated with the widget, this is what you want.

If, however, you use curly braces instead, as in:

bind ... <Return> {validate $FN .editFr$FN.edit$FN}

whatever value is in the global variable FN *at the time the binding
fires* is what is passed to the validate proc. Rarely, this is a good
thing. Best practices says to not rely on this because you can't control
when the user is going to click on something.

I'm curious -- is this project just so you can learn Tcl, is it a
homework assignment, or is it a requirement of your job?

krith...@yahoo.com

unread,
Jan 13, 2006, 4:56:42 PM1/13/06
to
Hi
Thanks. I needed that!
I did understand your examples and was not sure about the list and
curly braces - how it was being used. It was with the other procedure
that was not setting the flag. The operation is with Return and TAB. It
is OK now
By the way , this is a requirement for my job! I am learning TCL on
the job while creating an application. it is not a HW assigment

Thanks
krithiga
Bryan Oakley wrote:

krith...@yahoo.com

unread,
Jan 13, 2006, 5:36:28 PM1/13/06
to
Hi
I have one more question on the widgets. Once the user enters data
and then hits the Done button which calls Clear_ALL button. When it
comes here all the field data are cleared. This I have done. But the
fields have to be cleared also, meaning they can show in the window but
internally they need to be cleared, because when the user types a part
no for the first field the rest of the fields are dependent on this
part no and the window will adjust based on the number fo fields. I
tried to use the variable associated with field name and cleared it bit
it is saying this error
window name "editFrsys_ser" already exists in parent
window name "editFrsys_ser" already exists in parent
while executing
"frame .editFr$FN -borderwidth 10"

Can you show me an example of how I can clear the field name

Thanks
krithiga

Gerald W. Lester

unread,
Jan 13, 2006, 5:48:30 PM1/13/06
to

The above shows you attempting redefine the widget, this is not required --
just set the value of the variable to {} to "clear" it.

krith...@yahoo.com

unread,
Jan 13, 2006, 6:04:54 PM1/13/06
to
Hi
Well this is an example:

SYS_PART nnnnn
the following fields come up based on nnnn
SYS_SER
MB_SER
PS_SER

When I press Clear ALL all data in fields are cleared. Now I come in
and type another number for SYS_PART and depending on the number the
rest of the fields can stay or bcome more or become less. So I did set
the varaible associated with field to "" at the beginning but stilll
says the error.

Thanks
krithiga

Bryan Oakley

unread,
Jan 13, 2006, 6:48:25 PM1/13/06
to

This example shows that you are trying to create a widget with a name
that is already in use by a widget.

Your "Clear_ALL" procedure probably needs to delete the widgets. That,
or before creating a widget you check for its existence:

if {![winfo exists .editFr$FN...]} {
# create the widget; it doesn't exist
frame ...
}

Here's a hint: create all the widgets that need to be "cleared" in a
frame. When you want to delete the widgets can can do something like:

eval destroy [winfo childiren $frame]

How many different types of parts do you have? If it's a small number of
distinct types, create all the forms ahead of time. You can create an
empty frame that serves as a placeholder. You can then use "place" to
put each frame on top of this placeholder. When the user picks a part,
you simply raise the appropriate frame. It's as if each form is a piece
of paper in a stack, and you take out the appropriate page and place it
on the top of the stack.

I suspect none of that makes sense to you, and I'm not going to type out
a full example. Just be aware there are other ways to handle a dynamic
set of forms other than to constantly destroy and recreate the widgets.

krith...@yahoo.com

unread,
Jan 16, 2006, 1:16:19 PM1/16/06
to
Hi
I was also thinking about creating forms. But there are many parts
and these may become more as we like to make application more generic.
When the Clear_ALL button is pressed I bring it back to the original
screen where if we type the part no the rest of the screen appears. The
reset_current_item clears all the variables and calls the refresh.

proc button_ClearAll {} {

reset_current_item

display_screen
update idletasks
focus .editFr1.edit1 ;# set focus to first entry box
startup
bind .editFr1.edit1 <Return> {validate_sys_part $dat; display_screen1}

}

proc refresh {} {
global keepVars

eval destroy [winfo children .]
foreach var [info globals] {
if {[lsearch $keepVars $var] == -1} {
global $var
unset $var
}

But the requirement is when we press clear ALL is to clear all the
varaibles and leave the screen as it is and when I type the part no for
the first field the rest of the screen needs to adjust. How do I do
this without destroying the widgets in the above procedures. Checking
for its existence?

Thanks
krithiga

Bryan Oakley

unread,
Jan 16, 2006, 2:57:39 PM1/16/06
to
krith...@yahoo.com wrote:

> But the requirement is when we press clear ALL is to clear all the
> varaibles and leave the screen as it is and when I type the part no for
> the first field the rest of the screen needs to adjust. How do I do
> this without destroying the widgets in the above procedures. Checking
> for its existence?

I've been hesitating to do this but I think the best thing to do is to
give you a complete working example.

In this example, all form data is stored in the global array named
'data'. Typing in a part number and pressing return will show a form
based on the part number. I define two different types of parts: widget
and gadgets. Widgets have part numbers ending in '1'; all other part
numbers are gadgets.Part numbers are converted to all uppercase when you
press return.

It's not perfect, and I would do things differently if I had the time.
This is not production quality code -- it's just a quick hack. Yet, I
think it illustrates all the things you are trying to accomplish.

Save the following code to a file and run it with wish. If you enter a
part number that ends in "1" you'll get one type of form; all other
part numbers give you a different type of form.

----- save everything below this line -----

set fields(widget) {name color}
set fields(gadget) {name length width height}

set data(partnum) "" ;# current part number
set data(type) "" ;# current part type

proc main {} {

# This defines the place for the part number
#
frame .partnum
label .partnum.l -text "Part number:"
entry .partnum.e -textvariable data(partnum) -width 32
pack .partnum.l -side left
pack .partnum.e -side left

# this defines the buttons
frame .buttons
button .buttons.clear_form -text "Clear form" \
-command [list clear_form]
button .buttons.clear_all -text "Clear all" \
-command [list clear_all]
pack .buttons.clear_form .buttons.clear_all -side left

# this defines the part-specific form; the contents
# of the form are different for different part numbers
# so it will be filled in later
frame .form -borderwidth 1 -relief sunken

pack .partnum -side top -fill x
pack .form -side top -fill both -expand 1
pack .buttons -side bottom -fill x

# when the user enters a part number and presses return
# we are to display the form for that part; a tab merely
# goes to the top of the current form
bind .partnum.e <Return> new_partnum
bind .partnum.e <Tab> "focus_to_form;break"

wm geometry . 600x400
}

proc new_partnum {} {
global data
set data(partnum) [string toupper $data(partnum)]
show_form
}

proc show_form {} {
global fields data

# remove any existing form
reset_form

# widgets have a part number ending in "1"; gadgets are all others
set partnum $data(partnum)
if {[string match {*1} [string trim $partnum]]} {
set type "widget"
} else {
set type "gadget"
}

set frame .form-$type
set data(type) $type

# Only create the form if it doesn't already exist
if {![winfo exists $frame]} {
frame $frame -borderwidth 2 -relief groove
foreach field $fields($type) {
label $frame.l-$field -text "$field:"
entry $frame.e-$field -textvariable data($field)
grid $frame.l-$field $frame.e-$field
grid configure $frame.l-$field -sticky e
grid configure $frame.e-$field -sticky ew
# have <Return> perform the same behavior of <Tab>
bind $frame.e-$field <Return> [bind all <Tab>]
}
set lastrow [lindex [grid size $frame] 1]
grid rowconfigure $frame $lastrow -weight 1
grid columnconfigure $frame 1 -weight 1
}

# clear the data in the form
clear_form

# make sure this form is the one that is visible
pack $frame -in .form -side top -fill both -expand y
raise $frame
update idletasks

focus_to_form
}

proc focus_to_form {} {
global data fields
set type $data(type)
if {$type == ""} return
set frame .form-$type
focus $frame.e-[lindex $fields($type) 0]
}

proc reset_form {} {
if {![winfo exists .form]} return
if {[pack slaves .form] == {}} return
foreach child [pack slaves .form] {
pack forget $child
}
}

proc clear_form {} {
global fields data
set type $data(type)
if {![info exists fields($type)]} return

foreach field $fields($type) {
set data($field) ""
}

focus_to_form
}

proc clear_all {} {
global data
array unset data
set data(partnum) "" ;# current part number
set data(type) "" ;# current part type
reset_form
}

main

krith...@yahoo.com

unread,
Jan 18, 2006, 2:41:33 PM1/18/06
to
Hi
Thanks a ton! . I was able to create the forms with the example

Also how to set the cursor to the Done Button after the last field i.e
how to check if last field?

>From the data entered in the entries I created a text file and then to
load the text file into the widget fields - I am stuck

Here is the code. We need to store the data from the file to the array
and the first element has to got the first field. How do I do this?
proc LoadTextFileData {} {

global address SCRDEF SCR1 FN
set fileName [tk_getOpenFile -initialdir "" -title "Open Text Data
File" -defaultextension ".txt"]
puts $fileName
if {$fileName != ""} {
set LTF [open $fileName r]
}
while {![eof $LTF]} {
set FD [gets $LTF]
puts $FD

set $address(partnum) [lindex $FD 1]
set SCR1 $address(SCR1)
set scr2 [lindex $SCR1 0 ]
set scr3 [split $scr2 , ]
foreach field $scr3 {

Bryan Oakley

unread,
Jan 18, 2006, 3:16:07 PM1/18/06
to
krith...@yahoo.com wrote:
> Hi
> Thanks a ton! . I was able to create the forms with the example
>
> Also how to set the cursor to the Done Button after the last field

Assuming you mean "move the mouse pointer to the Done button", you
can't. Well, you can, but it's really bad UI design. If you want to do
that you'll have to figure it out for yourself. The concept is called
"warping the mouse". Don't do it; your users will hate you.

If you mean "move the keyboard focus", it's no different than setting
the focus to an entry widget -- use the "focus" command.

What people normally do is bind <Return> to the done button and <Escape>
to the cancel button. However, you're using <Return> for something
else, so simply move keyboard focus to the Done button with the focus
command and that will be good enough.

> i.e
> how to check if last field?

It's trivial, and this really is something you need to figure out for
yourself. You're the one creating the fields so just use some logic. We
try not to do other peoples jobs here. If you come up with a solution
that isn't working for a technical reason let us know and we'll be glad
to help.

>
>>From the data entered in the entries I created a text file and then to
> load the text file into the widget fields - I am stuck
>

You aren't having a Tcl problem, you are having a logic problem. You
should be able to figure it out. I don't mean to be rude, but you're
supposed to be a professional programmer yet you keep asking very
fundamental questions that any programmer should be able to figure out.
Again, we're not here to do your job. We try to solve technical problems
but this isn't a technical problem.

To read a file you use open and either gets or read. It appears you've
discovered that already. Your fields are associated with the 'address'
array so it surely must be obvious what to do.

I will give one hint, though... Your code contains this:

> set FD [gets $LTF]
> puts $FD
>
> set $address(partnum) [lindex $FD 1]

Unless you are absolutely certain the data in the file is a Tcl list
(because you wrote it out as a Tcl list and are certain it wasn't
modified in any way), don't use lindex. lindex requires you give it a
list, and will throw an error if the line of data isn't a list. A very
large percentage of all real world data does not meet the criteria of
being a list.

So, follow this rule: *never* use list commands on raw data.

If, after applying all those bits of advice you are still stuck, tell us
specifically how Tcl isn't working the way you think it should. If, for
example, you are getting a Tcl error you don't understand, show us the
exact error and the lines of code causing the error and we can help.

krith...@yahoo.com

unread,
Jan 19, 2006, 5:42:06 PM1/19/06
to
HI
OK.. Here is what I came up for last field and to move Focus to Done
Button and it did not move focus

set AS [array size address]
for { set i 0 } {$i < $AS} {incr i} {

validate_entry $SNM $FN


if {$Errflag == 1} {
puts "I am here because of error"
return -code break

} else {

puts "I am here before focus next"
focus [tk_focusNext $w]

}
}
focus -lastfor .buttonFr.xml
}

So for the last element it should come out of the loop and then move
focus to Done button.
Is ths focus command correct?

This is how Done button is

button .buttonFr.xml -text "Done" -command button_Done -padx 20 -font
{ariel 14 bold}

Thanks
krithiga
Bryan Oakley wrote:

Bryan Oakley

unread,
Jan 19, 2006, 6:59:27 PM1/19/06
to
krith...@yahoo.com wrote:
> HI
> OK.. Here is what I came up for last field and to move Focus to Done
> Button and it did not move focus
> ...
> focus -lastfor .buttonFr.xml

> }
>
> So for the last element it should come out of the loop and then move
> focus to Done button.
> Is ths focus command correct?
>

No.

By including "-lastfor" you are requesting that the focus most to the
most recent widget that had focus rather than specifically to
.buttonFr.xml. This behavior is documented in the focus man page.

Remove the "-lastfor" option.

krith...@yahoo.com

unread,
Jan 20, 2006, 12:46:36 PM1/20/06
to
Hi
PK I removed the last for. But what happens is everytime an entry is
made it moved FOcus to Done button. I checked the logic and for the
last element it comes out of for loop but does not set focus to Done
Button

Thanks
krithiga
Bryan Oakley wrote:

Bryan Oakley

unread,
Jan 20, 2006, 1:20:28 PM1/20/06
to
krith...@yahoo.com wrote:
> Hi
> PK I removed the last for. But what happens is everytime an entry is
> made it moved FOcus to Done button. I checked the logic and for the
> last element it comes out of for loop but does not set focus to Done
> Button

I don't keep copies of your code laying around and you don't post enough
to show all the logic so the best I can do is give generic advice.

your code needs to look something like this:

# code where you create the entry fields
foreach field ... {
...
entry $entry ...
bind $entry <Return> [list xxx $field ...]
...
}
...
# code that is called when user presses <Return> in
# an entry widget
proc xxx {field args} {
....
if {[is_last_field $field]} {
focus $done_button
} else {
# send focus to next entry field
...
}
}

It's then just a simple matter of defining the proc is_last_field to
either return 1 (yes, this is the last field) or 0 (no, this isn't the
last field). Focus will then either go to the done button or the next
entry field.

krith...@yahoo.com

unread,
Jan 21, 2006, 1:59:05 PM1/21/06
to
Hi
Thanks. I put in my code in the previous post and hence I did not
repost it. I used the foreach loop. I am still working on it
Also in your previous example when we change forms meaning when
another part number is typed is it possible to make a sound when the
number changes from current screen to a different screen? How do we do
this in the example?

Thanks
krithiga

Bryan Oakley

unread,
Jan 21, 2006, 2:19:05 PM1/21/06
to
krith...@yahoo.com wrote:
> Hi
> Thanks. I put in my code in the previous post and hence I did not
> repost it. I used the foreach loop. I am still working on it
> Also in your previous example when we change forms meaning when
> another part number is typed is it possible to make a sound when the
> number changes from current screen to a different screen? How do we do
> this in the example?

Tcl, all by itself, has no commands for making sounds.

You can include the "snack" extension which has commands for playing
sound files. Depending on what version of tcl you're using, you may
already have snack. Search using google for the keywords "tcl" and "snack".

Depending on your platform, you can also exec a command that plays a
sound file.

krith...@yahoo.com

unread,
Jan 25, 2006, 3:52:40 PM1/25/06
to
Hello
In the example you provided to set the form, I am setting my form the
following way. I derive the fields from a list.

set partnum $address(partnum)


if {[string compare $DefaultScreen startup] == 0} {

puts " I am in display screen1"
set SCR1 startup
} else {
set SCR1 $DefaultScreen

}


set frame .form-$SCR1

set SCR2 [lindex $SCRDEF($SCR1) 0 ]
puts $SCR2

set SCR3 [split $SCR2 , ]

set address(SCR3) $SCR3

If I do a foreach FN $SCRDEF($SCR1) - It is returning a whole string
and FN is returned as {sys_ser, mb_ser...}
Then I do foreach FN $SCR3 {

..set up frame. etc

}

In the Clear_ALL procedure

proc button_ClearAll {} {
global SCRDEF address SCR1 partnum Errflag SCR3 FN
array unset address
set address(partnum) "" ;# current part number
set address(SCR3) "" ;# current part type
}

When I do this the fields in the address(SCR3) are not getting cleared
unless I do a foreach field . What I am doing inorrectly here?

Thanks
krithiga

Bryan Oakley

unread,
Jan 25, 2006, 4:09:31 PM1/25/06
to
krith...@yahoo.com wrote:
> Hello
> In the example you provided to set the form, I am setting my form the
> following way. I derive the fields from a list.
>
> set partnum $address(partnum)
> if {[string compare $DefaultScreen startup] == 0} {
> puts " I am in display screen1"
> set SCR1 startup
> } else {
> set SCR1 $DefaultScreen
>
> }
>
>
> set frame .form-$SCR1
>
> set SCR2 [lindex $SCRDEF($SCR1) 0 ]
> puts $SCR2
>
> set SCR3 [split $SCR2 , ]
> set address(SCR3) $SCR3
>
> If I do a foreach FN $SCRDEF($SCR1) - It is returning a whole string
> and FN is returned as {sys_ser, mb_ser...}
> Then I do foreach FN $SCR3 {
>
> ..set up frame. etc
>
> }

If your data is truly {sys_ser, mb_ser..} Then FN will have the value
"sys_ser," "mb_ser," etc (note the trailing commas as part of the data).
So, you create array elements like address(sys_ser,), etc. but in your
clear_all function you're trying to reset addrss(sys_ser), etc.

Tcl has no way of knowing that you use commas and spaces to separate
your list items, so when you do a foreach over a string tcl only splits
on spaces and the commas become part of each element.

Since your items are separated by both a comma and space, you either
need to use the textutil::split function in tcllib to convert the string
to a list, or do some other processing of some sort.

krith...@yahoo.com

unread,
Jan 25, 2006, 7:49:24 PM1/25/06
to
Hi
The fields are sys_ser, mb_ser that is another field from an array. I
am putting the data in address(FN) and then clearing it in Clear_ALL
procedure whihc is not getting cleared unless I use a foreach, which is
OK in most part. But if the user presses a Clear at the beginning of
the field then it cannot read the variable SCR3 as it is set only on a
return TAB.
Also how do I make the Clear Button and Done button appear only in
the second form only? This was another thing I thought about. Do I use
winfo exist on Done button Frame? Or is there a way to dull out the
Clear Button for the first form and make active only when all fields
appear? If so please let me know how.

Thanks
kc

Bryan Oakley

unread,
Jan 25, 2006, 8:31:19 PM1/25/06
to
krith...@yahoo.com wrote:
> Hi
> The fields are sys_ser, mb_ser that is another field from an array. I
> am putting the data in address(FN) and then clearing it in Clear_ALL
> procedure whihc is not getting cleared unless I use a foreach, which is
> OK in most part. But if the user presses a Clear at the beginning of
> the field then it cannot read the variable SCR3 as it is set only on a
> return TAB.

As I said in my other post, because of bugs in your data, the fields are
being created as "sys_ser,", "mb_sr," etc *with* the commas. That is why
the foreach works (you replicate the bug in two places) but directly
setting the variables with, for example, 'set address(sys_ser) ""' fails
-- address(sys_ser) does not exist but address(sys_ser,) does exist.

As for not being able to read the SCR3 variable until you press return ,
that is a design bug you'll have to work out for yourself.

> Also how do I make the Clear Button and Done button appear only in
> the second form only? This was another thing I thought about. Do I use
> winfo exist on Done button Frame? Or is there a way to dull out the
> Clear Button for the first form and make active only when all fields
> appear? If so please let me know how.

If you read the button man page you'll see that there is a "-state
disbled" option. Most often, you always want the button there and simply
change the state to normal or disabled as appropriate.

krith...@yahoo.com

unread,
Feb 9, 2006, 8:24:01 PM2/9/06
to
Hi
I have to create another form for a repair section which requires to
double the fields for label and entry? as one is for the bad part
number and one for the replaced part.

label $frame.l-$FN -text "$FN1:" -padx 0 -font {ariel 14 bold}


Is there a way to double this field with putting a different text? (eg
-text "REPAIR $FN1" )

Thanks
kc

Bryan Oakley

unread,
Feb 9, 2006, 9:20:44 PM2/9/06
to
krith...@yahoo.com wrote:
> Hi
> I have to create another form for a repair section which requires to
> double the fields for label and entry? as one is for the bad part
> number and one for the replaced part.
>
> label $frame.l-$FN -text "$FN1:" -padx 0 -font {ariel 14 bold}
>
>
> Is there a way to double this field with putting a different text? (eg
> -text "REPAIR $FN1" )
>

I have no idea what you mean by "double this field". Can't you just
create a second label?

label $frame.l1-$FN ...
label $frame.l2-$FN ...


--
Bryan Oakley
http://www.tclscripting.com

krith...@yahoo.com

unread,
Feb 10, 2006, 12:55:57 PM2/10/06
to
Hi
What I mean by doubling is the fields like MB_SER, PS_SER should
appear as

MB_SER:
REPAIR MB_SER:

So Each field should appear twice, the second one with a different
text.

Also sone fields need to grayed out meaning they cannot enter info

I tried the label label $frame.l2-$FN and it accepts this.

Thanks
krithiga

krith...@yahoo.com

unread,
Mar 2, 2006, 8:30:55 PM3/2/06
to
Hello
Is there a way to put a default value in the . entry command in tk to
have an NA value and then override it with the value the user enters?

Also I am trying to create another form instead of doubling which will
have all the fields like

ORIG MB_SER
ORIG PS_SER

and then store these entries and after these are entered and user hits
DONE, create another form with

REPLACED MB_SER
REPLACED PS_SER

The Form with ORIG will remain on the screen. Is it possible to do this
and if you can please provide an example that would be helpful

Thanks
krithiga

krith...@yahoo.com

unread,
Mar 3, 2006, 5:34:11 PM3/3/06
to
Hello
Can some one please respond to this posting if possible?

Thanks
kc

Bryan Oakley

unread,
Mar 3, 2006, 6:27:52 PM3/3/06
to
krith...@yahoo.com wrote:
> Hello
> Is there a way to put a default value in the . entry command in tk to
> have an NA value and then override it with the value the user enters?

It's hard to understand what you are asking. Yes, you can put a default
value into an entry widget:

entry .e -textvariable foo
set ::foo "this is the default value"

You could also do:

.e insert 0 "this is the default value"

Does that answer your question?

> Also I am trying to create another form instead of doubling which will
> have all the fields like

I don't understand what you mean by "instead of doubling".

You can certanly create multiple forms in multiple frames and pack/place
or grid whichever one the user is supposed to see.

krith...@yahoo.com

unread,
Mar 3, 2006, 7:57:59 PM3/3/06
to
Hello
Yes.
If there is a default value entered and if the user types in something
will the value be overridden automatically? Or the entry fileld has to
be modified?

What I meant by doubling is

MB_SER

ORIG MB_SER

I am creating 2 filelds ( 2 labels, entries) for the same fileld but
with different text. This is what I meant by doubling

Is there an example of a multiple form and how to pack/place or grid?

Thanks
kc

krith...@yahoo.com

unread,
Mar 3, 2006, 8:15:54 PM3/3/06
to
Hi
I need to use the word duplicate. I am sorry. I am duplicating the
fields and using a diffierent text name
MB_SER
ORIG MB_SER

Now, since the users can make errors we are required to have 2 forms
which are the same
One form will have

ORIG MB_SER
ORIG PS_SER

After user enters data in these fields and hits DONE, it goes to
another form which has same fields but different text
REPLACE MB_SER
REPLACE PS_SER

I used the same procedure to use this but since the form exists with
the frame it is not creating another form. I do not want to destroy the
original form but add to the form with the same fields.
How do I accomplish this?

Thanks
kc

Bryan Oakley

unread,
Mar 3, 2006, 9:18:25 PM3/3/06
to
krith...@yahoo.com wrote:
> Hello
> Yes.
> If there is a default value entered and if the user types in something
> will the value be overridden automatically? Or the entry fileld has to
> be modified?

I suggest you try it and see.

>
> What I meant by doubling is
>
> MB_SER
>
> ORIG MB_SER
>
> I am creating 2 filelds ( 2 labels, entries) for the same fileld but
> with different text.

What text is different? The label? Why create two fields for the same
"fileld" (field?)?

I'm sorry, your requirements just aren't clear.

I would suggest first trying to create two forms that are both visible
at the same time. Get that working, then we can show you how to modify
your code so only one form is visible at a time.

Bryan Oakley

unread,
Mar 3, 2006, 9:22:17 PM3/3/06
to

Put the forms in different frames.

proc create_form {frame} {
frame $frame
label $frame.label1 ...
entry $frame.entry1 ...
label $frame.label2 ...
entry $frame.entry2 ...
}

create_form .form1
create_form .form2

if {[show_form_1?]} {
pack forget .form2
pack .form1
} else {
pack forget .form1
pack .form2
}

There are many different ways to do it. For example, you could pack one
form then use place to place the other form directly on top. Then you
would use "raise" and "lower" to pick which one is visible.

Donald Arseneau

unread,
Mar 4, 2006, 3:13:43 AM3/4/06
to
Bryan Oakley <oak...@bardo.clearlight.com> writes:

> krith...@yahoo.com wrote:
> > I need to use the word duplicate. I am sorry. I am duplicating the
> > fields and using a diffierent text name
> > MB_SER
> > ORIG MB_SER
>

> Put the forms in different frames.
>
> proc create_form {frame} {
> frame $frame
> label $frame.label1 ...
> entry $frame.entry1 ...
> label $frame.label2 ...
> entry $frame.entry2 ...
> }

And filling in a bit of the "...", we'd probably want another parameter
or two. Let's assume the parameters are in three arrays, to facilitate
block-copies. Then it makes sense to name the arrays by the identifier
"ORIG", "REPLACE",

proc create_form {frame ident} {
set arr "[string trim $ident]values"
set txtid [string trim $ident]
if { [string length $txtid] } {
append txtid " "
}
frame $frame
label $frame.label1 -text "${txtid}MB_SER" ...
entry $frame.entry1 -textvariable $arr(MB_SER) ...
label $frame.label2 -text "${txtid}PS_SER" ...
entry $frame.entry2 -textvariable $arr(PS_SER) ...
}

create_form .form1 ""
create_form .form2 "ORIG"
create_form .form3 "REPLACE"

Copy values like

array set values [array get ORIGvalues]
... edit ... edit ...
array set REPLACEvalues [array get values]


--
Donald Arseneau as...@triumf.ca

Bryan Oakley

unread,
Mar 4, 2006, 8:15:42 AM3/4/06
to
Donald Arseneau wrote:
> proc create_form {frame ident} {
> set arr "[string trim $ident]values"
> set txtid [string trim $ident]
> if { [string length $txtid] } {
> append txtid " "
> }
> frame $frame
> label $frame.label1 -text "${txtid}MB_SER" ...
> entry $frame.entry1 -textvariable $arr(MB_SER) ...

You're making too much work for yourself. Just use a single array for
the textvariables, and another one for the labels:

label $frame.label1 -text $text($ident,MB_SER) ...
entry $frame.entry1 -textvariable $data($ident,MB_SER)

Rarely, if ever, does it make sense to use dynamically created variable
names; it just makes the code harder to read.

krith...@yahoo.com

unread,
Mar 6, 2006, 7:48:36 PM3/6/06
to
Hello
Thanks. I tried using this as the form for the frame in my code is
determined by a variable.
I did not use show_form as I did not understand what show_form_1?
meant?

When I have one form and hit DONE button it creates the other form with
REPLACED but ORIG goes away. How does the orig form still stay on the
screen and how to use place to place in the above example?

Thanks
krithiga

krith...@yahoo.com

unread,
Mar 6, 2006, 9:04:17 PM3/6/06
to
Hi
If I do this way

if { $ident == "ORIGINAL" } {
puts "ident is $ident"
button .buttonFr.orig -text "ORIGINAL SERIAL NOS FINISH" -command
Orig_Done -padx 20 -font {ariel 14 bold}
pack .buttonFr.orig -side left -padx 60 -anchor center
.buttonFr.orig configure -background lightgreen
} else {
pack forget .buttonFr.orig
button .buttonFr.xml -text "DONE" -command button_Done -padx 20 -font
{ariel 14 bold}
pack .buttonFr.xml -side left -padx 60 -anchor center
.buttonFr.xml configure -background lightgreen
}

and then use

if { $ident == "ORIGINAL" } {
#pack $frame -in .form -side top -fill both -expand y
pack .form1 -side top -fill both -expand y
# raise $frame
update idletasks
} else {
#pack $frame -in .form -side bottom -fill both -expand y
pack .form3 -side top -fill both -expand y
# raise $frame
update idletasks
}
Then the ORIG and REPLACE both appear but what happens is the ORIG and
REPLACE serial nos show up below the Clear and Done button. the clear
and DONE button should be below. If use pack $frame this does not
happen meaning the Clear and DONE button is below but the REPLACED
screen overrides the ORIG screen
Can you explain what pack $frame does and pack .form does and what I am
doing wrong?

krith...@yahoo.com

unread,
Mar 7, 2006, 1:32:17 PM3/7/06
to
Hello
Can someone please respond to this posting of why the problem is
occuring and the difference in usage of pack?

Thanks
krithiga

0 new messages