TAdvMoneyEdit - editing float numbers

Hello, I have spent several hours trying to find how to setup TAdvMoneyEdit component today, but I wasn't able to correctly enter float numbers in a user friendly manner using this component. I think the component is in a very alpha state and it is not usable at all.

 
I have tried different settings of main control properties (EditType, PrecisionDisplay, Precision) and the test results follows. In this test I have tryed to enter "1.1" both the direct way in the edit field and through the calculator (results are separated by the slash). The green results are correct.
 
Direct entry of 1.1:
  1. EditType:=etFloat
    1. PrecisionDisplay:=pdNormal, Precision:=0 ... 11 / 1.1
    2. PrecisionDisplay:=pdNormal, Precision:=2 ... 1.10 / 1.00*
    3. PrecisionDisplay:=pdShortest, Precision:=0 ... 11 / 11
    4. PrecisionDisplay:=pdShortest, Precision:=2 ... 1.1 / 1
  2. EditType:=etMoney
    1. PrecisionDisplay:=pdNormal, Precision:=0 ... 11 / 11
    2. PrecisionDisplay:=pdNormal, Precision:=2 ... 1.10 / 1.00*
    3. PrecisionDisplay:=pdShortest, Precision:=0 ... 11 / 11
    4. PrecisionDisplay:=pdShortest, Precision:=2 ... 1.1 / 11
  3. EditType:=etNumeric
    1. PrecisionDisplay:=pdNormal, Precision:=0 ... 11 / 1.1
    2. PrecisionDisplay:=pdNormal, Precision:=2 ... 11 / 1.1
    3. PrecisionDisplay:=pdShortest, Precision:=0 ... 11 / 1.1
    4. PrecisionDisplay:=pdShortest, Precision:=2 ... 11 / 1.1
  4. EditType:=etString
    1. PrecisionDisplay:=pdNormal, Precision:=0 ... 11 / 1.1
    2. PrecisionDisplay:=pdNormal, Precision:=2 ... 1.10 / 1.00*
    3. PrecisionDisplay:=pdShortest, Precision:=0 ... 11 / 11
    4. PrecisionDisplay:=pdShortest, Precision:=2 ... 1.1 / 11

*) entering "1.1" leads to value "1.001" that's rounded to 1.00

As you can see, no combination can be used because you would supply some manual to the user describing how to enter any correct value. It is not possible to setup the component in a way it will allow you enter correct number in both ways, i.e. with and without drop-down calculator.
The functionality of using basic math operations in the edit field doesn't work too (+, -, *, /). They work only in the dropped-down calculator.
This component could be very useful, please, can you correct it? And can you do it in a short time, or would I avoid using this component to be able to deliver my project to the customer?
You offer this single component for 95 EUR, but it in the current state it is a piece of code without any value.

Can you please clarify : "correctly enter float numbers"
What exactly do you want? If you want to enter 1.1, this means the DecimalSeparator should be '.' on your system and if you want to accept only one number after the decimal separator, you'd need to set AdvMoneyEdit.Precision = 1.

Hello, "1.1" was just an example. I can't correctly enter any decimal number and 1.1 was just the simplest example. The same behavior is for: any digits... decimal point... any digits. The main problem is in the TAdvEdit.SetText method, which works in really uncompatible way compared to the descendant class TAdvMoneyEdit needs :-)

So no matter you try 1.1, 12.34. 458.16, in every case you get different results if you enter numbers in the edit control and in the drop-down calculator. And sometimes you will get different result if you enter digits in the calculator using the keyboard and pressing the calculator buttons. It looks like the TAdvMoneyEdit was developed by someone else than TAdvEdit and probably there was added some extra functionality not compatible with TAdvMoneyEdit.



Why did I tried different precisions and edit types?

Look to the source code, the component sometimes changes its behavior based on these properties, where 0 means "unlimited" for float and "zero" for money, etc.



However for my example value 1.1 the expected result was 1.10 (or 1.1 when the precision was reset to zero). And there would be no difference if you enter value in the edit field or if you use the drop down calculator.

I'm sorry but I really don't understand what you say. I can enter a value like 1.1 without any issue.
Please describe EXACTLY and IN DETAIL what prevents you from entering 1.1 ?
You say you get a different result, so WHAT different result, I don't see any.
Are you using the latest version of this component?

Hello, I have written a very simple example demonstrating the problem.

You can download it here: http://www.oksoftware.cz/DownFile.aspx?fileid=209 (it is published on my web)
It contains both the source code and compiled EXE.
Every combination of properties allows to enter the decimal values by one of three expected methods (using keyboard, keyboard in the calculator or using just mouse in the calculator). But no settings work for all methods.
If you use the debugger, you will find there are some places in the TAdvMoneyEdit code that can't work together with TAdvEdit component.
For example look to the procedure TAdvMoneyEdit.FormKeyPress method:
The second line contains following piece of code:
  if Key = DecimalSeparator then
    if (pos(DecimalSeparator,Text)=0) then Text:=Text+DecimalSeparator;
But setting "Text" calls TAdvEdit.SetText method. This method contains following code:
  if PrecisionDisplay = pdNormal then
  begin
    if ((FPrecision > 0) or (FEditType = etMoney)) and (value <> '') then
    begin
      if (FEditType in [etMoney]) then
      begin
        if (Pos('-', value) > 0) then neg := '-' else neg := '';
        fmt := '%.' + IntToStr(FPrecision) + 'n';
        Value := Format(fmt, [EStrToFloat(Value)]);
      end;
      if (FEditType in [etFloat]) then
      begin
        fmt := '%.' + inttostr(FPrecision) + 'f';
        f := EStrToFloat(value);
        Value := Format(fmt, [f]);
      end;
    end;
  end
  else
  begin
    if (FEditType in [etFloat, etMoney]) then
    begin
      f := EStrToFloat(Value);
      Value := Format('%g', [f]);
    end;
  end;
I hope you don't need more detail description, because to every programmer must be clear that these two pieces of code can't allow any user to enter decimal numbers for most combinations of PrecisionDisplay, EditType and Precision properties.
However there exist some combinations that allow entering decimal numbers in some way. But it is not enough. Please, test it.
 
Versions of components:
TAdvMoneyEdit: 1.1.1.2
TAdvEdit: 2.9.2.0
These versions are included in the latest release of TMS Component Pack (6.2.2.0).

Hello, I am not sure if you were able to reproduce my problems, but the solution is very simple.

It is necessary to change just one line of code in the method TAdvMoneyEdit.FormKeyPress (AdvMoneyEdit.pas).
 
procedure TAdvMoneyEdit.FormKeyPress(Sender: TObject; var Key: Char);
begin
  CalcChange;
  if Key = DecimalSeparator then
    if (pos(DecimalSeparator,Text)=0) then Text:= SetTextDirect( Text+DecimalSeparator );
...
 
After this small change everything starts to work fine.
Please, can you place the correction above into your source code to avoid the problem in future releases of the component?
Thank you, Igor Gottwald

Hi again, this is my last post to the component TAdvMoneyEdit. I have added the calculation functionality of TMoneyEdit in the edit field (direct +, -, , / and % without using drop-down calculator). If you would like to add this functionality to the orginal component, please do following steps:

  • Add this private message event (declaration is procedure WMChar(var Msg: TWMKey); message WM_CHAR;)
    procedure TAdvMoneyEdit.WMChar(var Msg: TWMKey);
    begin
      case Msg.CharCode of
        Ord('c'),Ord('C'):begin
          Text:='0';
          newval:=true;
          prevop:=-1;
          SelectAll;
        end;
        Ord('+'):begin
          doplus;
          SelectAll;
        end;
        Ord('/'):begin
          dodiv;
          SelectAll;
        end;
        Ord('-'):begin
          domin;
          SelectAll;
        end;
        Ord('
    '):begin
          domul;
          SelectAll;
        end;
        Ord('='),VK_RETURN:begin
          doeq;
          SelectAll;
        end;
        Ord('%'):begin
          doperc;
          SelectAll;
        end;
      end;
      if (Msg.CharCode = Ord(DecimalSeparator)) then newval := False;
      inherited;
    end;
  • Call method doeq in TAdvMoneyEdit.CMExit
    procedure TAdvMoneyEdit.CMExit(var Message: TCMExit);
    begin
      doeq;
      inherited;
    end;
  • Reset newval flag after decimal point insertion in TAdvMoneyEdit.FormKeyPress
    procedure TAdvMoneyEdit.FormKeyPress(Sender: TObject; var Key: Char);
    begin
      CalcChange;
      if Key = DecimalSeparator then
        if (pos(DecimalSeparator,Text)=0) then {Text:=Text+DecimalSeparator;}
        begin
          SetTextDirect(Text+DecimalSeparator);
          newval := False;
        end;
    ...
  • Change logic of TAdvMoneyEdit.doperc so it calculates percents as expected:
    X + Y% = add Y% to the base X
    X - Y% = remove Y% from the base X
    X * Y% = calculate Y% of the base X
    X / Y% = calculate a base where Y% of the base is X
    procedure TAdvMoneyEdit.doperc;
    var
     e:extended;
    begin
     if Text='' then Text:='0';
     e:=strtofloat(StripThousandSep(Text));

     case prevop of
       1: begin
         e := prevvale/100;
         prevop := -1;
       end;
       3: begin
         if (e<>0) then e := prevval/(e/100) else e := 0;
         prevop := -1;
       end;
       else
         e:=prevval
    e/100;
     end;
     Text:=format('%g',[e]);

    end;

I hope these changes will be welcome, however I will be glad if you will import them into your component and I could install updates of TMP Component Package witout worry of loosing the functionality.

The only problem we could reproduce was typing a value while the calculator was displaying and your fix indeed solves this. We've also applied your improvement to allow to perform calculations by typing directly with the keyboard and without the calculator displayed. These improvements will be applied in the next update.

Thank you very much. Maybe my problems were affected by using Czech number format (the decimal separator is comma and the thousand separator is a space, i.e. 123,456.78 is written as 123 456,78), but I am not sure.

 
As I started to use updated code, I have discovered one more issue with direct calculations. If you try to enter a calculation like 100 * .25, it will enter 100 * 25 (without tde decimal separator).
To avoid this, it is necesarry to add an extra code change in the metod TAdvMoneyEdit.KeyPress:
Find the part of this code:
 
  {$IFNDEF DELPHI_UNICODE}
  if ((Text='0') or (newval)) and (key in ['0'..'9']) then
  {$ENDIF}
  {$IFDEF DELPHI_UNICODE}
  if ((Text='0') or (newval)) and (character.IsNumber(key)) then
  {$ENDIF}
  begin
    Text := Key;
    Key := #0;
    SelStart := 1 + Length(Prefix);
    SelLength := 0;
    Newval := False;
    Exit;
  end;
 
and change it to this:
 
  {$IFNDEF DELPHI_UNICODE}
  if ((Text='0') or (newval)) and (key in ['0'..'9']) then
  {$ENDIF}
  {$IFDEF DELPHI_UNICODE}
  if ((Text='0') or (newval)) and (character.IsNumber(key)) then
  {$ENDIF}
  begin
    if (not FCalcClosed) then
      Text := Key;
      Key := #0;
      SelStart := 1 + Length(Prefix);
      SelLength := 0;
    end;
    Newval := False;
    Exit;
  end;
 
And last small change is in the TAdvMoneyEdit.FormKeyPress. The green code was added to correctly handle decimal point in the open calculator:
 
procedure TAdvMoneyEdit.FormKeyPress(Sender: TObject; var Key: Char);
begin
  CalcChange;
  if Key = DecimalSeparator then
    if (pos(DecimalSeparator,Text)=0) then {Text:=Text+DecimalSeparator;}
    begin
      SetTextDirect(Text+DecimalSeparator);
      newval := False;
    end
    else if (newval) then
    begin
      SetTextDirect('0'+DecimalSeparator);
      newval := False;
    end;
As a check pattern I use the sequence: 20+5*0.5-.5/2+.+66.67%=
The result should be 10 in all cases (i.e. typing formula in the edit box or using the drop-down calculator both way: typing characters on the keybord or clicking on calculator buttons).