Solved

Mask Edit delphi for discount

Posted on 2010-11-24
13
1,016 Views
Last Modified: 2012-05-10
Hi,
I want to have a TEditMask to insert this values:
10+5+3
10+5
10%
-10

how I can do this?
0
Comment
Question by:ISIGest
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
13 Comments
 
LVL 25

Expert Comment

by:epasquier
ID: 34204735
With a TEditMask ???

Not possible. Obviously the many formats that you want to be able to edit are not compatible

But with a normal TEdit, you could well analyse the text and detect operators '+' /  '-'  and do operations, and pretty much the same for %
0
 
LVL 24

Expert Comment

by:jimyX
ID: 34204819
You can use the following but each line is separately set you can't have one mask for all of them at once:

!90+9+9;1;_           //_ the gap sign

!90%;1;_

-!90;1;_
0
 
LVL 25

Expert Comment

by:epasquier
ID: 34204909
That should do the trick :

ShowMessageFmt('Formula [%s] = %f', [ edtFormula.Text , GetSimpleFormulaValue( edtFormula.Text ) ] );

of course, that will not validate fully the mathematical syntax of the formula, it is well possible to accept formulas that are not valid, or return results not exactly correct. For example :
' 200 + 10%' will return 210% = 2,10 , so neither 200,1 which would be the correct mathematical result not 220% which would be what most regular guy wait ( 200 + 10% of 200 )

Function GetSimpleFormulaValue(F:String):Double;
 function FindOper(Ops:String):Integer;
 begin
  for Result:=1 to Length(F) do if Pos(F[Result],Ops)>0 Then Exit;
  Result:=0;
 end; 
   
 procedure DoOper(ValStr:String);
 begin
  ValStr:=Trim(ValStr);
  if ValStr='' Then Exit;
  Val:=StrToFloat(ValStr);
  Case Op of
   '+':Result:=Result+Val;
   '-':Result:=Result-Val;
   '%':Result:=Result/100;
  end;
 end; 
Var 
 P:Integer;
 Val:Double;
 Op:Char;
begin
 Result:=0;
 Op:='+';
 try
  Repeat
   P:=FindOper('+-%');
   if P>0 Then
    begin
     DoOper(LeftStr(F,P-1));
     Op:=F[P];
     F:=Copy(F,P+1,Length(F)); 
    end;
  Until P=0;
  DoOper(F);
 except
  Raise Exception.Create('Invalid Formula :'+F);
 end;  
end;

Open in new window

0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

Author Comment

by:ISIGest
ID: 34205361
When an user insert text like:  
------
10+5+3 is not a mathematical formula but a custom differten value.
10+5+3 is a cascade discount then like: 10% + 5% + 3% that in my TDataSet is stored in 3 separated fields Discount1, Discount2 and Discount3.
------
10% is like 10+5+3 but only the first discount that stored only in field "Discount1"
------
-10 is a value discount that stored in other field named "DiscountValue"

the mask edit is a SemiCalculated field the display and edit this possible values.

I hope I was clear.
0
 
LVL 25

Expert Comment

by:epasquier
ID: 34205461
what about that then :
!90%+9%+9%;1;_

that way, only the first value HAVE to be set. But you can't manage easily the -10 (fixed value) AND those % edit with a same maskedit, or you would end up with such a mask that it would be of no use, and simpler for users to have a plain TEdit that YOU control the syntax upon validation


0
 
LVL 24

Expert Comment

by:jimyX
ID: 34205600
What do you mean ? I did not get your point clearly.

If you mean -10%+-5%+-3% then here it is:
#99%+#9%+#9%;1;_

If you want it all positive 10%+5%+3%, then:
99%+9%+9%;1;_
0
 
LVL 25

Expert Comment

by:epasquier
ID: 34205648
JimyX : the point is that the discount can be set in 2 ways :
- by percentage, where 1 to 3 %age values can be added.
Atomic syntax : all positive values with "%" suffix, separated by "+"

- by fixed value, where only ONE NEGATIVE value is entered
0
 
LVL 25

Expert Comment

by:epasquier
ID: 34205761
I don't think using masked edit with such an input is a good idea.

Let the user input what he can and validate, TMaskEdit is not pretty with complex input
Function ValidateEntry(S:String):Boolean;
Var
 V:Double;
 i:integer;
 DiscA:Array[0..2] of Double; 
 L:TStringList;
begin
 if TryStrToFloat(S,V) Then
  begin
   DiscountValue:=V;
   Result:=True;
   Exit;
  end;
 L:=TStringList.Create;
 try
  L.Delimiter:='+';
  L.DelimitedText:=S;
  for i:=0 to 2 do
   begin
    if i<L.Count 
     Then DiscA[i]:=StrToFloat(Trim(StringReplace(L[i],'%','',[rfReplaceAll])))
     Else DiscA[i]:=0;
   end;  
  Discount1:=DiscA[0];
  Discount2:=DiscA[1];
  Discount3:=DiscA[2];
 except
  Result:=False;
 end;
 L.Free;
end;

Open in new window

0
 
LVL 25

Expert Comment

by:epasquier
ID: 34205787
in the first case (string is simple numeric value), you can check if V<0, and if it is not , 2 choices :
- you consider it is always a fixed value, but should be considered negative
- if the value is <100, consider it is a percentage value

so , entering "10" could be interpreted either as "-10" or "10% discount" , as you see fit
0
 
LVL 37

Expert Comment

by:Geert Gruwez
ID: 34206134
if the input is limited to a specific set :

just use a combobox with the possible entries

a lot easier ...
0
 
LVL 45

Expert Comment

by:aikimark
ID: 34206785
You might present them with a combobox control that states what kind of data they want to enter and then set the mask based on their selection.

You could let them enter the text without a mask and then apply different RegEx masks to see which one is most applicable/valid.

This UI problem stems from the multiple possible uses of a single control.  
0
 
LVL 25

Expert Comment

by:epasquier
ID: 34206974
> combo + dynamic mask edit
In that direction, one would even not present a single field for the 3 %age values, but 3 fields.
that would be what a "normal" programmer would do, because it fills the functionality needs and simplify the input validation.
but it is also not very clear for the user to have 2 or 4 fields.

> This UI problem stems from the multiple possible uses of a single control.

I perfectly understand where ISIGest needs come from...

I have some Retail users that WANT that kind of entry because that simplify the interface in a crowded screen (invoice input). That is just a major pain in the @$$ from a developer point of view, and the usability is relative, but for an unknown reason that is what cashiers are used to...

The only way to do it properly is then to custom-validate the entry
0
 
LVL 32

Accepted Solution

by:
Ephraim Wangoya earned 250 total points
ID: 34210871

Have you considered using three edit boxes, not the most ideal but might solve your problem.
Put them next to each other and remove the borders, or leave the borders

Here is a simple example
unit Unit3;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ComCtrls, StdCtrls, ExtCtrls;

type
  TForm3 = class(TForm)
    Panel1: TPanel;
    edtDiscount1: TEdit;
    edtDiscount2: TEdit;
    edtDiscount3: TEdit;
    procedure edtDiscount1KeyPress(Sender: TObject; var Key: Char);
    procedure edtDiscount2KeyPress(Sender: TObject; var Key: Char);
    procedure edtDiscount3KeyPress(Sender: TObject; var Key: Char);
  private
    function CountOf(AChar: Char; const AValue: string): Integer;
    procedure DisableEdits(AEdits: array of TEdit; AClear: Boolean = True);
    procedure EnableEdits(AEdits: array of TEdit);
  end;

var
  Form3: TForm3;

implementation

{$R *.dfm}

function TForm3.CountOf(AChar: Char; const AValue: string): Integer;
var
  I: Integer;
begin
  Result := 0;
  for I := 1 to Length(AValue) do
    if AChar = AValue[I] then
      Inc(Result);
end;

procedure TForm3.DisableEdits(AEdits: array of TEdit; AClear: Boolean);
var
  I: Integer;
begin
  for I := 0 to Length(AEdits) -1 do
  begin
    AEdits[I].Enabled := False;
    if AClear then
      AEdits[I].Text := '';
  end;
end;

procedure TForm3.edtDiscount1KeyPress(Sender: TObject; var Key: Char);
var
  S: string;
begin
  S := (Sender as TEdit).Text;
  if (Pos('-', S) > 0) or (Pos('%', S) > 0) then
    EnableEdits([edtDiscount2, edtDiscount3]);

  case Key of
    '0'..'9':
    begin
      if (Length(S) > 1) and (S[1] <> '-') then
        Key := #0
    end;
    '-':
    begin
      if Length(S) > 0 then
        Key := #0
      else
        DisableEdits([edtDiscount2, edtDiscount3]);
    end;
    '%':
    begin
      if (CountOf(Key, S) > 1) or (Pos('%', S) > 1) then
        Key := #0
      else
        DisableEdits([edtDiscount2, edtDiscount3]);
    end;
    '+':
    begin
      if (CountOf(Key, S) > 1) or (Pos('+', S) = 1) then
        Key := #0
      else
      begin
        edtDiscount2.SetFocus;
        edtDiscount2.SelectAll;
      end;
    end;
    #8, #27: ;
    else
      Key := #0
  end;
end;

procedure TForm3.edtDiscount2KeyPress(Sender: TObject; var Key: Char);
var
  S: string;
begin
  EnableEdits([edtDiscount3]);
  S := (Sender as TEdit).Text;
  case Key of
    '0'..'9':
    begin
      if Length(S) > 1 then
        Key := #0
    end;
    '+':
    begin
      if (CountOf(Key, S) > 1) or (Pos('+', S) = 1) then
        Key := #0
      else
      begin
        edtDiscount3.SetFocus;
        edtDiscount3.SelectAll;
      end;
    end;
    #8:
    begin
      if Length(S) <= 1 then
      begin
        edtDiscount1.SetFocus;
        edtDiscount1.SelectAll;
      end;
    end;
    #27, #127: ;
    else
      Key := #0
  end;
end;

procedure TForm3.edtDiscount3KeyPress(Sender: TObject; var Key: Char);
var
  S: string;
begin
  S := (Sender as TEdit).Text;
  case Key of
    '0'..'9':
    begin
      if Length(S) > 1 then
        Key := #0
    end;
    #8:
    begin
      if Length(S) <= 1 then
      begin
        edtDiscount2.SetFocus;
        edtDiscount2.SelectAll;
      end;
    end;
    #27, #127: ;
    else
      Key := #0
  end;
end;

procedure TForm3.EnableEdits(AEdits: array of TEdit);
var
  I: Integer;
begin
  for I := 0 to Length(AEdits) -1 do
    AEdits[I].Enabled := True;
end;

end.

//
object Form3: TForm3
  Left = 0
  Top = 0
  Caption = 'Form3'
  ClientHeight = 73
  ClientWidth = 245
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  PixelsPerInch = 96
  TextHeight = 13
  object Panel1: TPanel
    Left = 24
    Top = 24
    Width = 185
    Height = 28
    BevelInner = bvLowered
    Color = clWhite
    ParentBackground = False
    TabOrder = 0
    object edtDiscount1: TEdit
      Left = 4
      Top = 3
      Width = 22
      Height = 21
      BevelInner = bvNone
      BevelOuter = bvNone
      BorderStyle = bsNone
      TabOrder = 0
      OnKeyPress = edtDiscount1KeyPress
    end
    object edtDiscount2: TEdit
      Left = 29
      Top = 3
      Width = 22
      Height = 21
      BevelInner = bvNone
      BevelOuter = bvNone
      BorderStyle = bsNone
      TabOrder = 1
      OnKeyPress = edtDiscount2KeyPress
    end
    object edtDiscount3: TEdit
      Left = 55
      Top = 3
      Width = 25
      Height = 21
      BevelInner = bvNone
      BevelOuter = bvNone
      BorderStyle = bsNone
      TabOrder = 2
      OnKeyPress = edtDiscount3KeyPress
    end
  end
end

Open in new window

0

Featured Post

Free Tool: IP Lookup

Get more info about an IP address or domain name, such as organization, abuse contacts and geolocation.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
NetCrunch network monitor is a highly extensive platform for network monitoring and alert generation. In this video you'll see a live demo of NetCrunch with most notable features explained in a walk-through manner. You'll also get to know the philos…
Add bar graphs to Access queries using Unicode block characters. Graphs appear on every record in the color you want. Give life to numbers. Hopes this gives you ideas on visualizing your data in new ways ~ Create a calculated field in a query: …

717 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question