Want to win a PS4? Go Premium and enter to win our High-Tech Treats giveaway. Enter to Win

x
Solved

# Mask Edit delphi for discount

Posted on 2010-11-24
Medium Priority
1,046 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
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

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

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

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;
``````
0

Author Comment

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

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

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

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

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;
``````
0

LVL 25

Expert Comment

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 38

Expert Comment

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

just use a combobox with the possible entries

a lot easier ...
0

LVL 46

Expert Comment

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

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

Ephraim Wangoya earned 1000 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
``````
0

## Featured Post

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â€¦
Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGridâ€¦
Sometimes it takes a new vantage point, apart from our everyday security practices, to truly see our Active Directory (AD) vulnerabilities. We get used to implementing the same techniques and checking the same areas for a breach. This pattern can reâ€¦
In response to a need for security and privacy, and to continue fostering an environment members can turn to for support, solutions, and education, Experts Exchange has created anonymous question capabilities. This new feature is available to our Prâ€¦
###### Suggested Courses
Course of the Month11 days, 11 hours left to enroll

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

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