给个我编的类你,希望能帮上忙:
用法:
var
exp: TExpressionString;
begin
exp := TExpressionString.Create('3*2(8-1)-2/(3+7*1)');
if exp.validvalue then
结果 := exp.value;
===========================================================
unit k_Expression;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, k_Public;
type
RExpCode = record
Code: String;
Value: Double;
IsValid: Boolean;
Tag: Integer;
end;
TExpCodes = class
private
FAddAllow: Boolean;
FCodes: array of RExpCode;
FCount: Integer;
function GetCodeByName(const Name: String): RExpCode;
function GetCodeNames(Index: Integer): String;
function GetCodes(index: Integer): RExpCode;
function GetCodeTag(Index: Integer): Integer;
function GetCodeValue(Index: Integer): Double;
function GetCodeValueByName(const Name: String): Double;
function GetIsValid: Boolean;
function GetNameIndex(const Name: String): Integer;
function IndexOfName(const Name: String): Integer;
procedure SetCodeByName(const Name: String; Value: RExpCode);
procedure SetCodeNames(Index: Integer; Value: String);
procedure SetCodeTag(Index, Value: Integer);
procedure SetCodeValue(Index: Integer; Value: Double);
procedure SetCodeValueByName(const Name: String; Value: Double);
procedure SetCodes(index: Integer; Value: RExpCode);
procedure SetCount(Value: Integer);
public
constructor Create(iCount: Integer = 0);
destructor Destroy; override;
function ExistsName(const Name: string): Boolean;
procedure Add(const Name: String); overload;
procedure Add(const Name: String; iValue: Double); overload;
procedure Delete(const iName: string);
procedure Rename(const iName, nName: string);
procedure Clear;
property AddAllow: Boolean read FAddAllow write FAddAllow;
property CodeByName[const Name: String]: RExpCode read GetCodeByName write SetCodeByName;
property CodeNames[Index: Integer]: String read GetCodeNames write SetCodeNames;
property Codes[index: Integer]: RExpCode read GetCodes write SetCodes; default;
property Count: Integer read FCount write SetCount;
property Indexs[const Name: String]: Integer read GetNameIndex;
property IsValid: Boolean read GetIsValid;
property CodeTag[Index: Integer]: Integer read GetCodeTag write SetCodeTag;
property CodeValue[Index: Integer]: Double read GetCodeValue write SetCodeValue;
property CodeValueByName[const Name: String]: Double read GetCodeValueByName write SetCodeValueByName;
end;
TBOItemType = (boitOpt, boitCode, boitValue, boitUnknow);
TOptStr = string[1];
RBOItem = record
case ItemType: TBOItemType of
boitOpt: (Opt: TOptStr
;
boitCode: (Idx: Integer
;
boitValue: (Val: Double
;
boitUnknow: ();
end;
TBOItems = class
private
FItems: array of RBOItem;
FCodes: TExpCodes;
FCount: Integer;
function GetCodeReady: Boolean;
function GetItems(Index: Integer): RBOItem;
procedure SetCount(Value: Integer);
procedure SetItems(Index: Integer; Value: RBOItem);
public
constructor Create(iCount: Integer = 0; iCodes: TExpCodes = nil);
destructor Destroy; override;
function AssignValueTo(iTarget: TBOItems): Boolean;
procedure Add(iOpt: String); overload;
procedure Add(iIdx: Integer); overload;
procedure Add(iVal: Double); overload;
procedure Assign(Source: TBOItems);
procedure Clear;
property CodeReady: Boolean read GetCodeReady;
property Codes: TExpCodes read FCodes write FCodes;
property Count: Integer read FCount write SetCount;
property Items[Index: Integer]: RBOItem read GetItems write SetItems; default;
end;
TExpressionString = class
private
// private
FBOItems: TBOItems;
FCodeAllow: Boolean;
FCodes: TExpCodes;
FCodesCount: Integer;
FExpStr: String;
FExtract: Boolean;
FNewCodes: Boolean;
FValidExp: Boolean;
FValidValue: Boolean;
FValue: Double;
FValueFractionDigits: Integer;
function Calculate(iBOList: TBOItems; var Value: Double): Boolean;
function GetBOExpStr: String;
function GetValidValue: Boolean;
function GetValue: Double;
function IsDigitString(iStr: String): Boolean;
function IsValidCode(iStr: String): Boolean;
function LevelOf(iOpt: String): Integer;
procedure SetCodeAllow(Value: Boolean);
procedure SetExpStr(Value: String);
procedure SetValueFractionDigits(Value: Integer);
protected
// protected
property BOItems: TBOItems read FBOItems;
public
// public
constructor Create(iExpr: String = ''; iCodeList: TExpCodes = nil);
destructor Destroy; override;
function ValueOfExpr(iExpr: string): Double;
property BOExpStr: string read GetBOExpStr;
property CodeAllow: Boolean read FCodeAllow write SetCodeAllow;
property Codes: TExpCodes read FCodes write FCodes;
property ExpStr: String read FExpStr write SetExpStr;
property Extract: Boolean read FExtract write FExtract;
property ValidExp: Boolean read FValidExp;
property ValidValue: Boolean read GetValidValue;
property Value: Double read GetValue;
property ValueFractionDigits: Integer read FValueFractionDigits write SetValueFractionDigits;
end;
implementation
//=========================================================================
//=========================================================================
// TExpCodes:
//=========================================================================
//=========================================================================
constructor TExpCodes.Create(iCount: Integer = 0);
begin
inherited Create;
FAddAllow := True;
FCount := 0;
Count := iCount;
end;
destructor TExpCodes.Destroy;
begin
inherited;
end;
function TExpCodes.ExistsName(const Name: string): Boolean;
begin
Result := IndexOfName(Name) > -1;
end;
function TExpCodes.GetCodeByName(const Name: String): RExpCode;
var
i: Integer;
begin
i := IndexOfName(Name);
if i > -1 then
Result := FCodes
else begin
Result.Code := '';
Result.Value := 0;
end;
end;
function TExpCodes.GetCodeNames(Index: Integer): String;
begin
if (Index > -1) and (Index < FCount) then
Result := FCodes[Index].Code
else
Result := '';
end;
function TExpCodes.GetCodes(index: Integer): RExpCode;
begin
Result := FCodes[index];
end;
function TExpCodes.GetIsValid: Boolean;
var
i: Integer;
begin
Result := True;
if FCount > 0 then begin
for i := 0 to FCount - 1 do
Result := Result and FCodes.IsValid;
end;
end;
function TExpCodes.GetCodeTag(Index: Integer): Integer;
begin
if (Index > -1) and (Index < FCount) then
Result := FCodes[Index].Tag
else
Result := -1;
end;
function TExpCodes.GetCodeValue(Index: Integer): Double;
begin
if (Index > -1) and (Index < FCount) then
Result := FCodes[Index].Value
else
Result := 0;
end;
function TExpCodes.GetCodeValueByName(const Name: String): Double;
var
i: Integer;
begin
i := IndexOfName(Name);
if i > -1 then
Result := FCodes.Value
else
Result := 0;
end;
function TExpCodes.GetNameIndex(const Name: String): Integer;
begin
Result := IndexOfName(Name);
if Result = -1 then
Add(Name);
end;
function TExpCodes.IndexOfName(const Name: String): Integer;
begin
for Result := 0 to FCount - 1 do
if FCodes[Result].Code = Name then
Break;
if Result = FCount then
Result := -1;
end;
procedure TExpCodes.Add(const Name: String);
begin
if FAddAllow then begin
SetCount(FCount + 1);
FCodes[FCount - 1].Code := Name;
end;
end;
procedure TExpCodes.Add(const Name: String; iValue: Double);
begin
if FAddAllow then begin
SetCount(FCount + 1);
with FCodes[FCount - 1] do begin
Code := Name;
Value := iValue;
IsValid := True;
end;
end;
end;
procedure TExpCodes.Clear;
begin
if FAddAllow then
SetCount(0);
end;
procedure TExpCodes.Delete(const iName: string);
var
i, x: Integer;
begin
x := IndexOfName(iName);
if x > -1 then begin
for i := x + 1 to FCount - 1 do
Codes[i - 1] := FCodes;
SetCount(FCount - 1);
end;
end;
procedure TExpCodes.Rename(const iName, nName: string);
begin
SetCodeNames(IndexOfName(iName), nName);
end;
procedure TExpCodes.SetCodeByName(const Name: String; Value: RExpCode);
begin
SetCodes(IndexOfName(Name), Value);
end;
procedure TExpCodes.SetCodeNames(Index: Integer; Value: String);
begin
if (Index > -1) and (Index < FCount) then
FCodes[Index].Code := Value;
end;
procedure TExpCodes.SetCodeTag(Index, Value: Integer);
begin
if (Index > -1) and (Index < FCount) then
FCodes[Index].Tag := Value;
end;
procedure TExpCodes.SetCodeValue(Index: Integer; Value: Double);
begin
if (Index > -1) and (Index < FCount) then begin
FCodes[Index].Value := Value;
FCodes[Index].IsValid := True;
end;
end;
procedure TExpCodes.SetCodeValueByName(const Name: String; Value: Double);
begin
SetCodeValue(IndexOfName(Name), Value);
end;
procedure TExpCodes.SetCodes(index: Integer; Value: RExpCode);
begin
if (Value.Code <> '') and (-1 < Index) and (Index < FCount) then begin
FCodes[Index].Code := Value.Code;
FCodes[Index].Value := Value.Value;
FCodes[Index].IsValid := Value.IsValid;
FCodes[Index].Tag := Value.Tag;
end;
end;
procedure TExpCodes.SetCount(Value: Integer);
var
i: Integer;
begin
if FAddAllow and (FCount <> Value) then begin
if Value <= 0 then begin
FCount := 0;
SetLength(FCodes, FCount);
end else begin
SetLength(FCodes, Value);
if FCount < Value then
for i := FCount to Value - 1 do
FCodes.IsValid := False;
FCount := Value;
end;
end;
end;
//=========================================================================
//=========================================================================
// TBOItems:
//=========================================================================
//=========================================================================
constructor TBOItems.Create(iCount: Integer = 0; iCodes: TExpCodes = nil);
begin
inherited Create;
FCount := 0;
SetCount(iCount);
FCodes := iCodes;
end;
destructor TBOItems.Destroy;
begin
inherited;
end;
function TBOItems.AssignValueTo(iTarget: TBOItems): Boolean;
var
i: Integer;
tboi: RBOItem;
begin
Result := (FCount > 0);
if Result then begin
if iTarget.Count <> FCount then
iTarget.Count := FCount;
for i := 0 to FCount - 1 do begin
case FItems.ItemType of
boitOpt:
begin
tboi.ItemType := boitOpt;
tboi.Opt := FItems.Opt;
end;
boitCode:
begin
if (FCodes <> nil) and FCodes[FItems.Idx].IsValid then begin
tboi.ItemType := boitValue;
tboi.Val := FCodes[FItems.Idx].Value;
end else begin
Result := False;
Break;
end;
end;
boitValue:
begin
tboi.ItemType := boitValue;
tboi.Val := FItems.Val;
end;
boitUnknow:
begin
Result := False;
Break;
end;
end;
iTarget := tboi;
end;
end;
end;
function TBOItems.GetCodeReady: Boolean;
var
i: Integer;
begin
Result := True;
for i := 0 to FCount - 1 do
if FItems.ItemType = boitCode then
Result := Result and FCodes[FItems.Idx].IsValid;
end;
function TBOItems.GetItems(Index: Integer): RBOItem;
begin
if (Index > -1) and (Index < FCount) then
Result := FItems[Index]
else
Result.ItemType := boitUnKnow;
end;
procedure TBOItems.Assign(Source: TBOItems);
var
i: Integer;
begin
if FCount <> Source.Count then
SetCount(Source.Count);
for i := 0 to FCount - 1 do begin
FItems.ItemType := Source.ItemType;
case FItems.ItemType of
boitOpt: FItems.Opt := Source.Opt;
boitCode: FItems.Idx := Source.Idx;
boitValue: FItems.Val := Source.Val;
end;
end;
end;
procedure TBOItems.SetCount(Value: Integer);
var
i: Integer;
begin
if FCount <> Value then
if FCount > 0 then begin
if Value <= 0 then begin
FItems := Copy(FItems, 0, 1);
FCount := 0;
end else begin
if FCount > Value then
FItems := Copy(FItems, 0, Value)
else begin
SetLength(FItems, Value);
for i := FCount - 1 to Value - 1 do
FItems.ItemType := boitUnKnow;
end;
FCount := Value;
end;
end else if Value > 0 then begin
SetLength(FItems, Value);
for i := 0 to Value - 1 do
FItems.ItemType := boitUnKnow;
FCount := Value;
end;
end;
procedure TBOItems.SetItems(Index: Integer; Value: RBOItem);
begin
if (Index > -1) and (Index < FCount) then begin
FItems[Index].ItemType := Value.ItemType;
case Value.ItemType of
boitOpt: FItems[Index].Opt := Value.Opt;
boitCode: FItems[Index].Idx := Value.Idx;
boitValue: FItems[Index].Val := Value.Val;
end;
end;
end;
procedure TBOItems.Add(iOpt: String);
begin
Inc(FCount);
SetLength(FItems, FCount);
FItems[FCount - 1].ItemType := boitOpt;
FItems[FCount - 1].Opt := iOpt;
end;
procedure TBOItems.Add(iIdx: Integer);
begin
Inc(FCount);
SetLength(FItems, FCount);
FItems[FCount - 1].ItemType := boitCode;
FItems[FCount - 1].Idx := iIdx;
end;
procedure TBOItems.Add(iVal: Double);
begin
Inc(FCount);
SetLength(FItems, FCount);
FItems[FCount - 1].ItemType := boitValue;
FItems[FCount - 1].Val := iVal;
end;
procedure TBOItems.Clear;
begin
SetCount(0);
end;
//=========================================================================
//=========================================================================
// TExpressionString:
//=========================================================================
//=========================================================================
constructor TExpressionString.Create(iExpr: String = ''; iCodeList: TExpCodes = nil);
begin
inherited Create;
FCodeAllow := False;
FValueFractionDigits := 0;
if iCodeList = nil then begin
FNewCodes := True;
FCodes := TExpCodes.Create;
end else begin
FNewCodes := False;
FCodes := iCodeList;
end;
FBOItems := TBOItems.Create(0, FCodes);
if iExpr = '' then
FCodesCount := 0
else
SetExpStr(iExpr);
end;
destructor TExpressionString.Destroy;
begin
if FNewCodes then
FCodes.Free;
inherited;
end;
function TExpressionString.Calculate(iBOList: TBOItems; var Value: Double): Boolean;
var
v1, v2: Double;
tv: array of Double;
i, n: Integer;
begin
n := 0;
Result := True;
for i := 0 to iBOList.Count - 1 do begin
case iBOList.ItemType of
boitOpt:
begin
if n > 1 then begin
v1 := tv[n - 2];
v2 := tv[n - 1];
Dec;
tv := Copy(tv, 0, n);
case iBOList.Opt[1] of
#33: //!
begin
if v2 = 0 then
v1 := 1
else
v1 := 0;
Inc;
SetLength(tv, n);
end;
#37: //%
begin
if v2 = 0 then begin
Result := False;
Break;
end else
v1 := v1 - (Trunc(v1 / v2) * v2);
end;
#38: //&
begin
if (v1 = 0) and (v2 = 0) then
v1 := 0
else
v1 := 1;
end;
#42: //*
v1 := v1 * v2;
#43: //+
v1 := v1 + v2;
#45: //-
v1 := v1 - v2;
#47: ///
begin
if v2 = 0 then begin
Result := False;
Break;
end else
v1 := v1 / v2;
end;
#58: //:
begin
if n < 2 then begin
Result := False;
Break;
end else begin
if tv[n - 2] = 0 then
v1 := v2;
Dec;
tv := Copy(tv, 0, n);
end;
end;
#60: //<
begin
if v1 < v2 then
v1 := 1
else
v1 := 0;
end;
#61: //=
begin
if v1 = v2 then
v1 := 1
else
v1 := 0;
end;
#62: //>
begin
if v1 > v2 then
v1 := 1
else
v1 := 0;
end;
#63: //?
begin
if v1 = 0 then
tv[n - 1] := 0
else
tv[n - 1] := 1;
Inc;
SetLength(tv, n);
v1 := v2;
end;
#92: ///
v1 := Trunc(v1 / v2);
#124: //|
begin
if (v1 <> 0) or (v2 <> 0) then
v1 := 1
else
v1 := 0;
end;
end;
tv[n - 1] := v1;
end else begin
if (n = 1) and (iBOList.Opt[1] = #33) then begin
if tv[0] = 0 then
tv[0] := 1
else
tv[0] := 0;
end else begin
Result := False;
Break;
end;
end;
end;
boitValue:
begin
Inc;
SetLength(tv, n);
tv[n - 1] := iBOList.Val;
end;
else
begin
Result := False;
Break;
end;
end;
end;
Result := Result and (n = 1);
if Result then
if FValueFractionDigits > 0 then
Value := FloatRound(tv[0], FValueFractionDigits)
else
Value := tv[0];
end;
function TExpressionString.GetBOExpStr: String;
var
i: Integer;
begin
Result := '';
if ValidExp then
for i := 0 to FBOItems.Count - 1 do begin
case FBOItems.ItemType of
boitOpt:
Result := Result + FBOItems.Opt;
boitCode:
Result := Result + FCodes[FBOItems.Idx].Code;
boitValue:
Result := Result + FloatToStr(FBOItems.Val);
else
Result := Result + '<?UNKNOW?>';
end;
end;
end;
function TExpressionString.GetValidValue: Boolean;
begin
Result := (FBOItems.Count > 0) and ((FCodesCount = 0) or (FBOItems.CodeReady));
FValidValue := False;
if Result then
GetValue;
end;
function TExpressionString.GetValue: Double;
var
til: TBOItems;
begin
if not FValidValue then begin
til := TBOItems.Create;
FValidValue := FBOItems.AssignValueTo(til) and Calculate(til, FValue);
til.Free;
end;
if FValidValue then
Result := FValue
else
Result := 0;
end;
function TExpressionString.IsDigitString(iStr: String): Boolean;
// '0':48, '9':57
// '+':43, '-':45
// '.':46
var
i, DotCnt: Integer;
a: Char;
begin
Result := True;
DotCnt := 0;
for i := 1 to Length(iStr) do begin
a := iStr;
if a = #46 then begin
Inc(DotCnt);
Result := (DotCnt = 1);
end else if (a < #48) or (a > #57) then
Result := ((a = #43) or (a = #45)) and (i = 1) and (Length(iStr) > 1);
if Result = False then
Break;
end;
end;
function TExpressionString.IsValidCode(iStr: String): Boolean;
begin
Result := (Length(iStr) > 0) and (iStr[1] in [#95, #65..#90, #97..#122, #128..#254]);
end;
{#33:!, #37:%, #38:&, #42:*, #43:+, #44:,, #45:-, #47:/
, #58::, #60:<, #61:=, #62:>, #63:?, #92:/, #124:|}
{?: | & ! <=> +- */%/
1 2 3 4 5 6}
function TExpressionString.LevelOf(iOpt: String): Integer;
begin
Result := -1;
case iOpt[1] of
#63, #58: Result := 1;
#124: Result := 2;
#38: Result := 3;
#33: Result := 4;
#60..#62: Result := 5;
#43, #45: Result := 6;
#42, #47, #37, #92: Result := 7;
end;
end;
function TExpressionString.ValueOfExpr(iExpr: string): Double;
begin
ExpStr := iExpr;
Result := Value
end;
procedure TExpressionString.SetCodeAllow(Value: Boolean);
begin
if FCodeAllow <> Value then begin
FCodeAllow := Value;
if FCodeAllow then begin
if FCodesCount > 0 then begin
FValidExp := FBOItems.Count > 0;
if FValidExp and FBOItems.CodeReady then
GetValue;
end;
end else
if FCodesCount > 0 then begin
FValidExp := False;
FValidValue := False;
end;
end;
end;
procedure TExpressionString.SetExpStr(Value: String);
var
i, j, kn, lt, ls: Integer;
c: Char;
t, cs, ts: string;
b, OptExpect: Boolean;
pvExpItems: TStrings;
stk: TStrings;
begin
FBOItems.Clear;
if FNewCodes then
FCodes.Clear;
FCodesCount := 0;
FExpStr := Value;
pvExpItems := TStringList.Create;
// FExtract: Boolean;
FValidExp := False;
FValidValue := False;
FValue := 0.0;
kn := 0;
t := '';
cs := ' ';
b := True;
OptExpect := False;
for i := 1 to Length(Value) do begin
c := Value;
cs[1] := c;
case c of
#32:
begin
if t = '' then
Continue
else if OptExpect then
b := False
else begin
pvExpItems.Add(t);
t := '';
end;
end;
#40:
begin
if OptExpect or (t <> '') then
b := False
else begin
Inc(kn);
pvExpItems.Add(cs);
end;
end;
#41:
begin
if kn = 0 then
b := False
else begin
if t = '' then
b := OptExpect
else if OptExpect then
b := False
else begin
pvExpItems.Add(t);
t := '';
end;
Dec(kn);
pvExpItems.Add(cs);
OptExpect := True;
end;
end;
{#33:!, #37:%, #38:&, #42:*, #43:+, #44:,, #45:-, #47:/
, #58::, #60:<, #61:=, #62:>, #63:?, #92:/, #124:|}
#43, #45:
begin
if OptExpect then begin
if t <> '' then
b := False
else begin
pvExpItems.Add(cs);
OptExpect := False;
end;
end else begin
if t <> '' then begin
pvExpItems.Add(t);
t := '';
end else
pvExpItems.Add('0');
pvExpItems.Add(cs);
end;
end;
#58:
begin
if pvExpItems.Count < 3 then
b := False
else begin
if t <> '' then begin
if OptExpect then
b := False
else begin
pvExpItems.Add(t);
t := '';
end;
end else
b := OptExpect;
if b then
for j := pvExpItems.Count - 1 downto 1 do
if pvExpItems[j] = '?' then
break
else if pvExpItems[j] = ':' then begin
b := False;
break;
end;
if b then
pvExpItems.Add(cs);
end;
end;
#33:
begin
b := (t = '') and (not OptExpect);
pvExpItems.Add(cs);
end;
#37, #38, #42, #47, #60, #61, #62, #63, #92, #124:
begin
if t = '' then
b := OptExpect
else if OptExpect then
b := False
else begin
pvExpItems.Add(t);
t := '';
end;
pvExpItems.Add(cs);
OptExpect := False;
end;
else
if (c = #46) or ((c > #47) and (c < #58)) or ((c > #64) and (c < #91)) or ((c > #96) and (c < #127)) or ((c > #127) and (c < #255)) then
t := t + cs
else
b := False;
end;
if not b then
Break;
end;
b := b and (kn = 0) and ((pvExpItems.Count > 0) or (t <> ''));
if b then begin
if t <> '' then
pvExpItems.Add(t);
stk := TStringList.Create;
for i := 0 to pvExpItems.Count - 1 do begin
ts := pvExpItems;
if IsDigitString(ts) then
FBOItems.Add(StrToFloat(ts))
else if IsValidCode(ts) then begin
if FNewCodes then begin
FCodes.Add(ts);
j := FCodes.Count - 1;
end else begin
j := FCodes.Indexs[ts];
if j < 0 then begin
b := False;
Break;
end;
end;
FCodes.CodeTag[j] := FBOItems.Count;
FBOItems.Add(j);
Inc(FCodesCount);
end else if (Length(ts) = 1) and (LevelOf(ts) > 0) then begin
if stk.Count > 0 then begin
lt := LevelOf(ts);
ls := LevelOf(stk[stk.Count - 1]);
while ls >= lt do begin
FBOItems.Add(stk[stk.Count - 1]);
stk.Delete(stk.Count - 1);
if stk.Count = 0 then
break
else
ls := LevelOf(stk[stk.Count - 1]);
end;
end;
stk.Add(ts);
end else if ts = '(' then
stk.Add(ts)
else if ts = ')' then begin
while (stk.Count > 0) and (stk[stk.Count - 1] <> '(') do begin
FBOItems.Add(stk[stk.Count - 1]);
stk.Delete(stk.Count - 1);
end;
if stk.Count > 0 then
stk.Delete(stk.Count - 1);
end else
Break;
end;
if b then begin
if stk.Count > 0 then
for i := stk.Count - 1 downto 0 do
FBOItems.Add(stk);
if FCodesCount = 0 then begin
FValidValue := Calculate(FBOItems, FValue);
FValidExp := FValidValue;
end else begin
FValidExp := FCodeAllow;
if FBOItems.CodeReady then
GetValue
else
FValidValue := False;
end;
end;
stk.Free;
end;
pvExpItems.Free;
end;
procedure TExpressionString.SetValueFractionDigits(Value: Integer);
begin
if FValueFractionDigits <> Value then begin
FValueFractionDigits := Value;
if FValidValue then
GetValue;
end;
end;
end.