Thư viện tri thức trực tuyến
Kho tài liệu với 50,000+ tài liệu học thuật
© 2023 Siêu thị PDF - Kho tài liệu học thuật hàng đầu Việt Nam

1001 Things You Wanted To Know About Visual FoxPro phần 3 pot
Nội dung xem thử
Mô tả chi tiết
92 1001 Things You Always Wanted to Know About Visual FoxPro
.Value = EVAL( .cAlias + '.' + .cField )
ENDIF
ELSE
*** Otherwise, save the current work area
*** before switching to the specified table
lnSelect = SELECT()
SELECT ( .cAlias )
*** And locate the specified record
LOCATE FOR UPPER( ALLTRIM( EVAL (.cField ) ) ) = UPPER( lcSoFar )
IF FOUND()
.Value = EVAL( .cAlias + '.' + .cField )
ENDIF
*** Restore the original work area
SELECT ( lnSelect )
ENDIF
ENDIF
At this point we have either found the desired record in cAlias or we are at the end of the
file. All that remains to be done is to reset the highlighted portion of the text box correctly and
refresh the controls in the parent container (if this was specified by setting .lRefreshParent =
.T.):
*** If we need to refresh the parent container do it here
IF .lRefreshParent
.RefreshParent()
ENDIF
*** Highlight the portion of the value after the insertion point
.SelStart = lnSelStart
lnSelLength = LEN( .Value ) - lnSelStart
IF lnSelLength > 0
.SelLength = lnSelLength
ENDIF
*** If we have refreshed the controls in the parent container,
*** there are timing issues to overcome
*** Even though .SelStart and .SelLength have the correct values,
*** the search box does not appear highlighted correctly without this delay
=INKEY( .1, 'H' )
ENDWITH
Notice the INKEY() command here, and take some time to read the comment above if you
haven't already. This problem is not specific to our incremental search text box and timing
issues like this are not uncommon in Visual FoxPro. (We have also run into it when displaying
multi-select list boxes in which the previous selections are highlighted. In that case, using
INKEY() in the form's refresh allows the list box to be highlighted correctly.) It is interesting to
note that the INKEY() command is not required in the code above when lRefreshParent = .F.
This lends support to the assumption that this is nothing more than a timing issue. The short
pause allows Visual FoxPro to catch up.
Numeric text box (Example: CH04.VCX::txtNum and txtNumeric)
Visual FoxPro has inherited some serious shortcomings with respect to entering numeric data
from its FoxPro ancestors. It's not too bad when the entire field is selected, and the number is
not formatted with separators. However, problems begin to occur when the insertion point is
Chapter 4: Basic Controls 93
not at the beginning of the displayed value. Sometimes the user is trying to type the number 10,
but all he can type is 1 and, with confirm set off, the value of the text box becomes 1 and the
cursor moves on to the next field. We have also seen the opposite problem. The user wants to
enter 3 but after typing 3 and exiting the control, the number 30 is displayed instead of the
intended 3. So what can a Visual FoxPro developer do to help?
There are a few workarounds to this problem. You could create a numeric text box to
select the entire field and remove any separators used to format the number. This code in the
text box's GotFocus method allows the number to be entered correctly:
WITH This
*** Save the input mask
.cOldInputMask = .InputMask
*** Remove separators from input mask
.InputMask = STRTRAN( .cOldInputMask, ',', '' )
*** Perform Visual FoxPro native GotFocus()
TextBox::GotFocus()
*** Select the entire field
.SelStart = 0
.SelLength = LEN( .cOldInputMask )
*** Don't let base class behavior reset SelStart/SelLength
NODEFAULT
ENDWITH
Since we need to change the text box's inputMask to accomplish this, we add a custom
property called cOldInputMask to hold the original inputMask assigned to the control. We will
need this property in the text box's LostFocus method in order to restore the formatting like so:
This.InputMask = This.cOldInputMask
Of course, we already have a text box class that correctly selects the entire field where you
tab into it or mouse-click on it. Our base class text box does this when SelectOnEntry = .T. So
all we have to do is base our numeric text box on our base class text box, set SelectOnEntry to
true, and put this code in its GotFocus method:
WITH This
*** Save the original input mask
.cOldInputMask = .InputMask
*** Remove separators from input mask
.InputMask = STRTRAN( .cOldInputMask, ',', '' )
*** Perform the parent class behavior
DODEFAULT()
ENDWITH
The numeric text box described above may be sufficient for you. It's easy to create, doesn't
contain a lot of code and works around the problems involved in entering numeric data
correctly. But wouldn't it be nicer to have a numeric text box that does calculator style entry
from right to left? We have seen several examples of such text boxes and, in our opinion, they
all suffer from the same shortcoming. Either the cursor can be seen flashing to the left as
characters appear from the right or there is no cursor at all. Both of these solutions tend to
make things confusing for the user. So we set out to create the ultimate Visual FoxPro numeric
94 1001 Things You Always Wanted to Know About Visual FoxPro
text box. And we very quickly discovered why none currently exists. It was HARD! So we
hope you find this useful as it is the result of entirely too many hours and too much blood,
sweat, and tears. Not only does it do calculator style entry, the cursor is also positioned on the
correct character. When the value in the text box is not selected, you can even delete or insert
individual digits in the middle of the number displayed in the text box.
The numeric text box is a simple control to use. Just drop it on a form, page or container
and set its ControlSource property. That's all! You don't even need to set its InputMask unless
you want the control to be unbound because it is capable of formatting itself when bound. The
way most numeric text boxes work is by changing the value into a character string,
manipulating the string and the InputMask and then re-converting the string to a numeric value.
However, our numeric text box is actually an unbound control (even though you can set it up
as if it were bound) and works because its value actually is a character string and is
manipulated as such. It uses custom code to update its ControlSource with the numeric
equivalent of the character string which is its value.
This example is designed to work either unbound or bound to a field in a table, cursor or
view. If you need to bind to a form property, the code will need a little modification to account
for it. An example of how to do this can be found in the UpdateControlSource method of the
spnTime class described later in this chapter.
The following, eight custom properties were added to our custom numeric text box. They
are all used internally by the control and you do not need to do anything with them explicitly.
Table 4.2 Custom properties of the numeric text box
Property Description
CcontrolSource Saves the controlSource if this is a bound control before it is unbound in the Init
method
Cfield Field name portion of ControlSource if it is bound
CinputMask Stores original inputMask when it is specified, otherwise stores the inputMask
constructed by the control
ColdConfirm Original setting of SET( 'CONFIRM' ) saved in GotFocus so it can be restored in
LostFocus.
ColdBell Original setting of SET('BELL') saved in GotFocus so it can be restored in
LostFocus
Cpoint Character returned by SET( 'POINT' )
Cseparator Character returned by SET( 'SEPARATOR' )
Ctable Table name portion of ControlSource if it is bound
LchangingFocus Flag set to suppress KEYBOARD '{END}' which is used to position the cursor at
the rightmost position in the text box. If we do this when the control is losing focus,
it messes up the tab order
NmaxVal Maximum value allowed in the control
The SetUp method, called by the TextBox's Init method, saves the content of the
ControlSource property to the custom cControlSource property before unbinding the control
from its ControlSource. It also determines, and sets up, the InputMask for the control. Even
though this code is executed only once when the text box is instantiated, we have put it in a
custom method to avoid coding explicitly in events whenever possible. Notice that we use