I currently have thus simple proc to check entry widgets are valid:
##-----------------------------------------------------------------------------
## Check the number in an entry widget is an integer ##------------------------------------------------------------------------------
proc ValidInt {val} {
return [expr {[string is integer $val]
|| [string match {[-+]} $val]} ]
} ##-----------------------------------------------------------------------------
However, I'd like to also validate the value is within a range,
so can I do something like:
proc ValidInt {val min max} {
return [expr {[string is integer $val] && ($val >= $min) && ($val <= $max) || [string match {[-+]} $val]} ]
}
But that isn't quite working. :-(
TIA, KevP.
On Wednesday, March 8, 2023 at 11:18:14â¯AM UTC, snosniv wrote:
I currently have thus simple proc to check entry widgets are valid:
##-----------------------------------------------------------------------------
## Check the number in an entry widget is an integer ##------------------------------------------------------------------------------
proc ValidInt {val} {
return [expr {[string is integer $val]
|| [string match {[-+]} $val]} ]
} ##-----------------------------------------------------------------------------
However, I'd like to also validate the value is within a range,
so can I do something like:
proc ValidInt {val min max} {
return [expr {[string is integer $val] && ($val >= $min) && ($val <= $max) || [string match {[-+]} $val]} ]
}
But that isn't quite working. :-(
TIA, KevP.
Perhaps I should add that all values will be positive, (maybe 0 or blank too).
I'm checking mins & secs amongst others, so secs will be either blank (I already check that & assign 0) or between 0 & 59,
and mins will be between 0 & 99 (also checked for blank & assigned 0). (e.g. I could have 2 mins & blank secs, or blank mins & 15 secs).
Other entry widgets will have different limits.
KevP.
At Wed, 8 Mar 2023 05:33:09 -0800 (PST) snosniv <[email protected]> wrote:
On Wednesday, March 8, 2023 at 11:18:14 AM UTC, snosniv wrote:
I currently have thus simple proc to check entry widgets are valid:
##-----------------------------------------------------------------------------
## Check the number in an entry widget is an integer ##------------------------------------------------------------------------------
proc ValidInt {val} {
return [expr {[string is integer $val]
|| [string match {[-+]} $val]} ]
} ##-----------------------------------------------------------------------------
However, I'd like to also validate the value is within a range,
so can I do something like:
proc ValidInt {val min max} {
return [expr {[string is integer $val] && ($val >= $min) && ($val <= $max)
|| [string match {[-+]} $val]} ]
}
But that isn't quite working. :-(
TIA, KevP.
Perhaps I should add that all values will be positive, (maybe 0 or blank too).
I'm checking mins & secs amongst others, so secs will be either blank (I already check that & assign 0) or between 0 & 59,
and mins will be between 0 & 99 (also checked for blank & assigned 0). (e.g. I could have 2 mins & blank secs, or blank mins & 15 secs).
Other entry widgets will have different limits.
KevP.If the "entry" is always going to be an integer (or blank==0), then maybe using a SpinBox (ttk::spinbox) might be a better choice. All of the data validation is implicit. (The spinbox also has incr/decr arrows on it, which is a UI convenience.)
--
Robert Heller -- Cell: 413-658-7953 GV: 978-633-5364
Deepwoods Software -- Custom Software Services
http://www.deepsoft.com/ -- Linux Administration Services [email protected] -- Webhosting Services
I currently have thus simple proc to check entry widgets are valid:
##-----------------------------------------------------------------------------
## Check the number in an entry widget is an integer ##------------------------------------------------------------------------------
proc ValidInt {val} {
return [expr {[string is integer $val]
|| [string match {[-+]} $val]} ]
} ##-----------------------------------------------------------------------------
However, I'd like to also validate the value is within a range,
so can I do something like:
proc ValidInt {val min max} {
return [expr {[string is integer $val] && ($val >= $min) && ($val <= $max)
|| [string match {[-+]} $val]} ]
}
But that isn't quite working. :-(
TIA, KevP.
snosniv <[email protected]> wrote:
I currently have thus simple proc to check entry widgets are valid:
##-----------------------------------------------------------------------------
## Check the number in an entry widget is an integer ##------------------------------------------------------------------------------
proc ValidInt {val} {
return [expr {[string is integer $val]
|| [string match {[-+]} $val]} ]
} ##-----------------------------------------------------------------------------
However, I'd like to also validate the value is within a range,
so can I do something like:
proc ValidInt {val min max} {
return [expr {[string is integer $val] && ($val >= $min) && ($val <= $max) || [string match {[-+]} $val]} ]
}
But that isn't quite working. :-(
TIA, KevP.If you read the [expr] man page, you'll see that the operators are
"grouped in decreasing order of precedence" therein. Reading further,
you will see that logical and (&&) has higher precedence than logical
or (||).
Your long comparison is (B as a standin for "boolean"):
B && B && B || B
Due to the precedence rules, this is effectively:
( B && B && B ) || B
Which means any time the boolean on the other side of the or is true,
the entire statement is true, regardless of what the and'ed booleans
produce.
Next, instrumenting your proc is a very useful technique for debugging
these sorts of issues. Do this, as a test:
proc ValidInt {val min max} {
puts "string is integer $val: [set b1 [string is integer $val]]"
puts "($val >= $min): [set b2 [expr {($val >= $min)}]]"
puts "($val <= $max): [set b3 [expr {($val <= $max)}]]"
puts "string match {\[-+]} $val: [set b4 [string match {[-+]} $val]]"
puts "combined clause: $b1 && $b2 && $b3 || $b4"
return [expr {[string is integer $val] && ($val >= $min) && ($val <= $max) || [string match {[-+]} $val]} ]
}
And then you can run tests to check the result, *and* see the
incremental buildup of the result inside the proc. And seeing that incremental buildup is often key to recognizing why "it does not work":
% ValidInt 0 1 2
string is integer 0: 1
(0 >= 1): 0
(0 <= 2): 1
string match {[-+]} 0: 0
combined clause: 1 && 0 && 1 || 0
0
Works
% ValidInt 5 1 2
string is integer 5: 1
(5 >= 1): 1
(5 <= 2): 0
string match {[-+]} 5: 0
combined clause: 1 && 1 && 0 || 0
0
Works
% ValidInt - 1 2
string is integer -: 0
(- >= 1): 0
(- <= 2): 1
string match {[-+]} -: 1
combined clause: 0 && 0 && 1 || 1
1
Presumably this fails (you did not give an example that failed, so I
had to hunt one down that presumably is a failure, and most of us would
not consider a lone "-" to be a valid number).
Why did it fail? Because the last, logical or, string match returned
true, and because of precedence, returned true for the entire
statement.
What you need to do is check first for "is integer", and only if "is
integer" passes, then check for <= and >=, i.e.:
return [expr {[string is integer $val] && ( ($val >= $min) && ($val <= $max) )}]
The reason is that <= and >= are dual use. They prefer numeric
comparisons, but fall back to string comparisons, and so - <= 2 becomes
"-" <= "2" (strings) because - is not an integer. So you want to
require that "is integer" be true before performing either range check. Nesting the range checks inside parenthesis and and'ing that to 'is
integer' sets the statement up so that 'is integer' must be true before
any of the range checks are tested.
Still having issues with this. :-(
I tried: ##-----------------------------------------------------------------------------
proc ValidIntRng {val min max} {
return [expr {[string is integer $val] && ( ($val >= $min) && ($val <= $max) )}]
} ##-----------------------------------------------------------------------------
But with this, when I type a 2 digit value, I cannot delete the first
digit, only the second? This seems odd behaviour!
snosniv <[email protected]> wrote:
Still having issues with this. :-(
I tried: ##-----------------------------------------------------------------------------
proc ValidIntRng {val min max} {
return [expr {[string is integer $val] && ( ($val >= $min) && ($val <= $max) )}]
} ##-----------------------------------------------------------------------------
But with this, when I type a 2 digit value, I cannot delete the first digit, only the second? This seems odd behaviour!Please provide a minimal and *complete* code sample.
I.e., just enough wrapper code to create an entry and to show how you
are connnecting the above to the entry.
## Sample code showing that entered 1st digit won't delete.
entry .enMINS -textvar warm_mins -width 2 -validate all -vcmd {ValidIntRng %P 0 99}
grid .enMINS -row 2 -column 1
proc ValidIntRng {val min max} {
return [expr {[string is integer $val] && (($val >= $min) && ($val <= $max))}]
}
On 3/9/2023 4:56 PM, snosniv wrote:
## Sample code showing that entered 1st digit won't delete.Just looking at this, if you want to be able to delete all characters in
entry .enMINS -textvar warm_mins -width 2 -validate all -vcmd {ValidIntRng %P 0 99}
grid .enMINS -row 2 -column 1
proc ValidIntRng {val min max} {
return [expr {[string is integer $val] && (($val >= $min) && ($val <= $max))}]
}
the entry widget, you will need to adjust the validator accordingly to
accept empty input:
proc ValidIntRng {val min max} {
expr {($val eq "") || ([string is integer $val] && ($val >= $min)
&& ($val <= $max))}
}
| Sysop: | Keyop |
|---|---|
| Location: | Huddersfield, West Yorkshire, UK |
| Users: | 715 |
| Nodes: | 16 (2 / 14) |
| Uptime: | 148:47:43 |
| Calls: | 12,091 |
| Calls today: | 4 |
| Files: | 15,000 |
| Messages: | 6,517,560 |