Jeff Childers wrote:
Hi Will,
First, let me say, WOW. And THANKS. This is thoughtful and extremely
helpful, not to mention a huge morale boost. What can I say?
You da man.Your weekend-long missive took all morning to respond to,
what with the aha!'s and all the notes I was taking. Below, find
questions/responses and a couple larger topics.Again, many thanks.
You're welcome!
>> Q: Is it your intention to make "home" and "end" mean
>> "home/end" of the current field, or just the whole
>> control? (either would be good, as right now, you can't
>> select and then hit backspace or delete...)In rev 0.0.6, I have home/end moving to the beginning / end of the
user-entered information. I think this is more intuitive and
works better than the way I was doing it. Does this seem 'right'?
Yes, in certain situations. However, I often think of a masked edit
control as a "multi-field" value for which you just happen to have 1
control, for "prettiness" of presentation. In these situations, I'd
probably want home and end to behave differently. For example, say
you have an IP address control, of the form:
###.###.###.###
In this situation, I'd like Tab to take me from one "field" to the
next, End take me to the end of that field, Home the beginning, etc.
I'd also like Ctrl-home to take me to the beginning of the 1st field,
and Ctrl-end to take me to the end of the last one, and shift to
select in either case. (A similar analogy is for text editors;
typically End takes you to end of line; Ctrl-End takes you to end
of file.) But, again, this may not be natural for a lot of uses of
the control. Perhaps this could be an option, or at least easily
done in a derivation by using the "OnEnd/Home" subroutine idea
I mentioned earlier...
>> ## 4. Mask characters [A,a,X,#] cannot appear in the format string
>> as literals. I haven't yet determined how difficult this would be,
>> but it seems to me that the logical means of doing this is to
>> have '\' be another special syntax characterThe trouble comes at the point of __isMaskChar and __isTemplateChar,
determining whether a given character is part of the mask or
template. Hmm, I -was- building a dictionary of positions to help
with this, maybe I should go back to that.... the key is the
character position, then whatever data needed, such as the template
character, allowed keys, etc. I could build the dictionary while
parsing out special characters such as \ and #{3} notation....
very Pythonistic!
This sounds like a reasonable solution, but if you ever allow
non-fixed-length templates, then you'll need to handle things a
bit differently... (For the #{n} notation, I'd just preprocess the
template, as it's just "shorthand" so you don't have to count
when you type.)
>> I'm curious about what you consider 'messing up' the
entered number?Harumph. The user can begin entering the a number, then click
'ahead' in the
mask to resume entry. This leaves a nasty space in the middle
of the number
that was giving value.strip() headaches. I replaced that with
string.replace(value," ","") and it seems to work better. I
*think* in rev
0.0.6 I have the most likely issues handled. <crosses fingers>
I'll try it when I see it.
>> The delete key should work, but it doesn't
I'm having challenges with this. It would be easy enough to remove
the current insertionpoint character, add a space at the end, and
"scroll" everything left through the mask. Trouble is, what happens
when a character that was legal in its current place would be
illegal in the new one? For example, consider the mask AAA###.
What happens when you press Del at position 2? The numbers cannot
be allowed to move into the character range.I considered enabling the first described behavior if the mask is
homogenous. For example, AAAAAA or ######. Then, they could delete and
scroll the contents to their hearts desire. But I would then
disable Del in heterogenous masks. What do you think?
Hmmm... I see the issue. Your solution seems reasonable, but it
might produce human factors issues in people not understanding why
sometimes delete works and sometimes it doesn't... My best advice
is to try some solutions and see how they feel. I'll bet though,
that it's fine; where you're doing complicated stuff like email
validation, you're likely to use X as the template char for all
positions, so this would satisfy the "homogenous" rule; for anything
heterogenous, (I can't think of a concrete example offhand), it will
probably be obvious why delete doesn't work.
However, you might also consider breaking up the input and
resplicing it with fillchar on delete, and making it so that
delete only works to the next template char. Consider:
12:59:59 AM
If I place the cursor between the 1 and 2, I *don't* want to
end up with a value of 15:95:95, but I might want (colored yellow)
1 :59:59 AM
Again, I think the only way to know for sure is to try some
strategies and see what feels best from a typing and intuition
perspective.
>> The "signed" integer demo allows you to type a minus, but once
>> entered, you can't erase it.They way I am handling it now is like a calculator; press -
again and the
sign changes. In 0.0.6, the '+' is also enabled to sign the control
positive.
Ah. That was NOT obvious; makes sense, but I think that it might
be more natural to allow backspace and/or delete to do the same
thing if the position is right for these special types of mask
(decimal and int.)
>> However, even using this, I find that what I really want is to go
>> to the end of what *I've* typed,I think I have this dialed in. You'll have to check and see
in 0.0.6. The
code for selecting text and the other shortcut keys are
really terrific.
Thanks again.
I look forward to it.
Should I worry about a submission for the wxWindows help
file? I'd be happy
to write through documentation if there were a place for it to go...
Not that I know of. The reason I started putting detailed (html)
help in the overview is that, as far as I know, the wxWindows
doc is reserved for those classes available in both wxWindows (ie.
C++ yechhh, ptui!) *and* wxPython. For our code, the only
beneficiaries are those that have seen the charm of the snake.
>> For the demo, I suggest a wxNotebook with your
>> various demos on the tabs of the notebook; then you can extend the
>> demo as much as you want by adding tabs as you run out of room...You like the notebook better than buttons opening wxFrames? I
thought about
the notebook but the demo's default size is so tiny...
Either way, but yes, I personally dislike the extra windows in the demo,
unless they're specifically to demonstrate dialog or frame
classes. Check out the wxNotebook demo in the demo; it puts the
tabs along the bottom, but you get the entire window to draw in.
It has something like 11 tabs on it, so there's no problem with
"enough room."
>> By convention, 8-space tabs are rarely used; most python I've seen
>> uses 4 space indenting and no tabs.I've been test-driving the Wing IDE and its indentation is
driving me crazy.
It has tons of options and I know it's in there somewhere but
damn if I can
find it. Out of curiousity, which IDE/editor are you using?
I use PythonWin from the win32 stuff Mark Hammond wrote to edit code,
as I work under MSW.
TOPIC: Character-level masking (time control, etc)
>> In order to use your control as the base class for such controls,
>> it would be necessary to disallow certain sequences and
control what
>> happens on erase.Here's the basic structure (as it is developing):
-- OnChar --
-- key action -- ie. valid keypress or
function key?
-- type action -- ie. date/int/decimal/char
-- 'validation' -- ie. set in/valid statusSay the user enters a '9'. First, it is checked for validity
within the
mask. Is it a "#" type? Yes, so go on to the type handler. Is
the control a
date type? Yes, check to see if an in-place formatting needs
to occur (e.g.
change '67' to '1967' if in the year position). Finally,
check to see if the
value is 'valid', also by type. In this case,
wxDateTime.Parse is called to
see if a valid date is found.As I follow your suggestion, an additional key filter would
occur based on
control type. So, is the '9' in the first position of the
month, day, or
year? If so, disallow entry. Is this right?
Yes, that seems right...
Or, what do you think about using the current structure, and
creating some
additional auto-formatting events? In this example, if the
user presses '9'
as the first char in the month or day position, it is
replaced with '09' and
insertion is moved to the next position. It would work the
same for time.So now, the user enters '3867' and the date autoformats their
entry on the
fly to '03/08/1967'. This does leave the sticky question of
what happens
when they enter '1' in the first position but want '01'.
Exactly. Take another example: the user types 101003.
They want 10/10/2003. But they might get 01/01/2003 with your
scheme. Perhaps there's a way to do this such that if the
key is simply not allowed in the position in question, then
auto-format rules are attempted; otherwise, the char is allowed,
and judgement is reserved.
Another question: if this is a preferred behavior,
how best to structure the code for ease of subclassing?
This is a tough one to answer off-the-cuff. Let me get
back to you on that...
But you might peruse wxTimeCtrl to see how it operates, to
answer this question. I'd want to attach the action
routines I wrote (or routines of similar ilk) to
derive wxTimeCtrl appropriately from your control. For
example, it would be nice to attach to the WXK_UP and
WXK_DOWN events to the IncrementValue() routine I wrote...
In a derivation, I'd want to be able to write something
like:
self.OnKeyUp = self._incrementValue
self.OnKeyDown = self._incrementValue
and then have my routines be able to determine the which
key was pressed, the current position, and then take appropriate
action on the value.
Currently, I have no specific time-type behavior in the
control; this seems
to me to already be handled nicely by wxTimeCtrl!
Yeah, but wouldn't it be nice to have wxTimeCtrl rewritten
so it's derived from wxMaskedEditTextCtrl?
TOPIC: Mixin Class Suggestions
Great idea, sounds scary. I haven't done -any- mixed-parent
classes yet
(still quite the foreign concept). I understand the idea but
have tons of
questions about the implementation. I may hold off on this
one, how about
version 2?
Sure, but it only sounds scary. One of the beauties of Python
is its ability to do multiple inheritance and just dynamically
add methods and attributes to classes and instances.
So, all a mixin is is a class that makes assumptions about the
availability of other functions that will also be present in
the class that it is "mixed in" to, and so cannot be used except
in conjunction with another such class. They don't, for instance,
have an __init__ method.
So basically you write:
class wxMaskedEditMixin:
def OnChar(self, event):
...
[...]
that is, the code looks just like the code you have now, but
all the functionality and attributes of the class you have now,
making assumptions about the availability of .SetValue,
.SetInsertionPoint, etc., and then you write:
class wxMaskedTextCtrl(wxTextCtrl, wxMaskedEditMixin):
def __init__(...
and you invoke methods of wxMaskedEditMixin just like you
do now, (ie. self.__configure() just works) and only code in
the stuff that is used to set parameterize the control behavior.
The difference is that you can "mix it in" to any other
class that operates under the same set of assumptions.
eg. wxMaskedComboBox(wxComboBox, wxMaskedEditMixin):
def __init__(...
should be very similar and minimal class definition.
(If you like, I can try to modify your next version for you as
at least a template on how to do this.)
Regards,
/Will Sadkin
Parlance Corporation