************************************************** *-- Class: txtnum (c:\projects\utils\numeric_textbox\numeric_textbox.vcx) *-- ParentClass: textbox *-- BaseClass: textbox *-- Time Stamp: 12/20/05 01:21:00 PM * DEFINE CLASS txtnum AS textbox Alignment = 1 Height = 23 SelectOnEntry = .T. Width = 156 *-- handle numerical or decimal part of value ( 'N' or 'D' ) ? ctextpart = "N" *-- flag needed to reset value after GotFocus cflag = "" *-- store number of decimals entered ndecimalsstored = 0 Name = "txtnum" PROCEDURE KeyPress LPARAMETERS nKeyCode, nShiftAltCtrl LOCAL cNumeric, cDecimal, cValue, cPoint, cSeparator, cCurrency, cCleanText LOCAL nTextLength, nDecimalValue, nPointPosition, nOldValue, nOldSetDecimals cPoint = SET("Point") cSeparator = SET("Separator") cCurrency = SET("Currency",2)+SET("Currency",3) cCleanText = TRIM(CHRTRAN(this.Text, cCurrency+'$' , SPACE( LEN(cCurrency)+1) )) &&&&strip some display formatting by InputMask,Format nTextLength = LEN( cCleanText ) nPointPosition = IIF( cPoint $ cCleanText , ATC(cPoint , cCleanText ) , LEN(cCleanText)+1) nOldValue = this.Value nOldSetDecimals = SET("Decimals") IF nPointPosition < LEN( cCleanText ) SET DECIMALS TO (nTextLength-nPointPosition) &&needed later for correct VAL() return ENDIF *get numeric and decimal part, if after GotFocus, start both with 0 ( string '' ) *when first allowed numeric key is pressed IF this.cFlag = 'gotfocus' AND nKeyCode >= 48 AND nKeyCode <= 57 AND nShiftAltCtrl = 0 cNumeric = '' cDecimal = '' this.cFlag = 'keypress' ELSE cNumeric = ALLTRIM(IIF( nPointPosition < LEN(cCleanText) , LEFT(cCleanText , nPointPosition-1) , cCleanText )) cNumeric = CHRTRAN(cNumeric, cSeparator , '') IF VAL( SUBSTR(cCleanText , nPointPosition+1) ) = 0 cDecimal = '' ELSE cDecimal = ALLTRIM( STR( VAL( SUBSTR(cCleanText, nPointPosition+1) ) )) ENDIF ENDIF DO CASE CASE this.ReadOnly CASE nKeyCode >= 48 AND nKeyCode <= 57 AND nShiftAltCtrl = 0 && 0 to 9 NODEFAULT IF this.cTextPart = 'N' &&handle numerical part IF NOT '*' $TRANSFORM( VAL(cNumeric + CHR(nKeyCode)) ; , CHRTRAN(cCleanText ,' 0123456789'+cSeparator+cPoint,'99999999999'+',.')) &&check overflow cNumeric = cNumeric + CHR(nKeyCode) ELSE *test set confirm , stay on textbox and beep if needed IF SET("Confirm") = 'ON' ??CHR(7) ELSE KEYBOARD '{TAB}' ENDIF ENDIF ELSE &&handle decimal part this.nDecimalsStored = this.nDecimalsStored + 1 IF this.nDecimalsStored > LEN(cCleanText)- nPointPosition IF SET("Confirm") = 'ON' ??CHR(7) ELSE KEYBOARD '{TAB}' ENDIF this.nDecimalsStored = this.nDecimalsStored - 1 ELSE cDecimal = STUFF(cDecimal, this.nDecimalsStored,1, CHR(nKeyCode)) ENDIF ENDIF cValue = cNumeric + cPoint + cDecimal this.Value = VAL(cValue) CASE nKeyCode = 43 && + NODEFAULT this.Value = ABS(this.Value) CASE nKeyCode = 45 && - NODEFAULT this.Value = -this.Value CASE CHR(nKeyCode) = SET("Point") AND cPoint $ cCleanText &&point pressed NODEFAULT this.cTextPart = 'D' &&will handle decimal part from now CASE INLIST( nKeyCode, 13, 9, 15, 5, 24, 18, 3) * Enter, Tab, Backtab, UArrow, DArrow, PgUp, PgDn - default beavior CASE nKeyCode = 7 && Del, reset value to 0 NODEFAULT cValue = '0' this.cTextPart = 'N' this.nDecimalsStored = 0 this.Value = VAL(cValue) CASE nKeyCode = 127 && BackSpace, delete from decimal part or from numeric part NODEFAULT *if selected( SelectOnEntry = .T.) reset value to 0 IF this.SelLength = LEN(this.Text) cValue = '0' + cPoint + '0' ELSE IF this.cTextpart ='N' IF LEN(cNumeric) >= 1 cNumeric = LEFT(cNumeric , LEN(cNumeric) - 1) ELSE cNumeric = '' ENDIF ELSE this.nDecimalsStored = this.nDecimalsStored - 1 IF this.nDecimalsStored < 0 && we need to step over the decimal point now this.nDecimalsStored = 0 this.cTextPart = 'N' IF LEN(cNumeric) >= 1 cNumeric = LEFT(cNumeric , LEN(cNumeric) - 1) ELSE cNumeric = '' ENDIF ENDIF cDecimal = STUFF(cDecimal, this.nDecimalsStored+1,1,'') ENDIF cValue = cNumeric + cPoint + cDecimal ENDIF this.Value = VAL(cValue) OTHERWISE * Ignore other keys, beep NODEFAULT ??CHR(7) ENDCASE IF this.cTextpart = 'N' this.SelStart = nPointPosition ELSE this.SelStart = nPointPosition + this.nDecimalsStored + 1 ENDIF SET DECIMALS TO (nOldSetDecimals) IF this.Value <> nOldValue this.InteractiveChange() &&this needed to be executed programatic ENDIF ENDPROC PROCEDURE GotFocus IF SET("Point") $ this.Text this.SelStart = ATC(SET("Point"),this.Text) ELSE this.SelStart = LEN(this.Text) ENDIF this.cTextPart = 'N' &&handle numeric part after GotFocus() this.cflag = 'gotfocus' this.nDecimalsStored = 0 &&so far typed decimals DODEFAULT() ENDPROC ENDDEFINE * *-- EndDefine: txtnum **************************************************