|
From: Joe E. <jen...@fl...> - 2005-09-20 02:40:10
|
Jeff Hobbs wrote:
> Take a simple validated entry widget:
>
> proc isValid {e str} {
> set ok [file isfile $str]
> $e configure -bg [expr {$ok ? "white" : "lightyellow"}]
> return 1
> }
OK -- so here you're using the validation facility strictly
to provide visual feedback, not to prevent the user from
entering an invalid value (which in this case is impossible
anyway -- you can't type a valid filename without typing
something that isn't a filename in between).
Part of the problem is that the return value of the
'-validatecommand' means two different things, depending on
context: (a) allow/don't allow this change, or (b) the value
is currently valid/invalid. (The ttk::entry manpage calls case
(a) "prevalidation" and case (b) "revalidation".)
But in this case, what you want to say is "the new value is
invalid, but accept the change anyway". There's no good
way to do this with the current API.
One possibility would be to use the 'alternate' state instead
of 'invalid' for visual feedback:
style map TEntry \
-foreground {alternate red} -background {alternate lightyellow} ;
proc checkFilename {e p} {
$e state [expr {[file isfile $p] ? "!alternate" : "alternate"}]
return 1
}
ttk::entry .e -validatecommand { checkFilename %W %P }
This isn't entirely satisfactory.
How about this: change the [ttk::entry] widget to generate
an <<EntryChanged>> virtual event whenever the value changes.
Then you could use:
ttk::entry .e -validate none -validatecommand { file isfile %P }
bind .e <<EntryChanged>> { %W validate }
That is: no prevalidation, but revalidate on every change.
The ttk::entry widget doesn't currently perform validation
when the linked -textvariable is set because this leads to
anomalies -- if the validation script(s) also set the variable,
the widget can't detect it since the original write trace
is still active. I can only think of two ways around this;
either don't worry about it and say "User beware", which is
basically what the core [entry] does; or schedule revalidation
as an idle handler, which leads to even more weirdness.
However, it *would* be safe to queue an <<EntryChanged>>
event in this condition.
* * *
I'm not sure how useful the current 'invalid/!invalid' state
logic is. The intent was to give visual feedback about the
current validity of the value, and also to prevent validation lockout:
if the widget becomes invalid, let the user type whatever he wants
until it's valid again. But if the application is using prevalidation,
the widget can't become invalid in the first place (barring bugs
in the app).
Maybe it should only set/clear the invalid bit after revalidation?
This would make your first approach work (use '-validate key',
set/clear the invalid bit in the -validatecommand, always return 1.)
Or maybe the widget should not set it at all, leaving it entirely
up to the app to do so?
--Joe English
jen...@fl...
|