Tutorial : Building a numeric edit control
Download the source of this component here :
type
TNumEdit = class(TCustomEdit)
private
{ Private declarations }
public
{ Public declarations }
published
{ Published declarations }
end;
|
1. The goals of the component TNumEdit
TNumEdit is an edit control which only can be used for numeric input.
Besides numeric values also a decimalseparator and minus (-) key may be entered. (1x each)
The input format is free, which means that at first no specific format is used like for
example the number of decimals.
The component offers the possibility to round the value on a given number of decimals.
The formatting takes place in the method DoExit.
If you do the formatting in the Change method it could cause unwanted behaviour because at
every keypress the value is formatted which changes the cursor position.
The Change method is added to format values which are 'stuffed' in the control by code.
2.Used techniques
New published properties
Besides the inherited properties of TCustomEdit there are a few new ones introduced :
All properties can be set in design- and runtime.
Override methods
The following methods are 'override' from TCustomEdit :
KeyPress
The property keypressed skips the onchange event formatting.
procedure TNumEdit.KeyPress(var Key: Char);
begin
KeyPressed := true; // Skip the Change Method
Inherited KeyPress(Key); // For the user OnKeyPressevent
//Check for Numeric and backspaces '-' and decimalseparator ','/'.'
if not (Key in ['0'..'9', '-', DecimalSeparator,#8]) then
begin
KeyPressed := False;
key:=#0; // Simulate a none keypress
beep;
end else //Check for existing ofdecimalsepatator and '-'
if ((Key = DecimalSeparator) or (key = '-')) and (Pos(Key, Text) > 0) then
begin
If Key = DecimalSeparator then
begin
SelStart := Pos(Key, Text);// Position Cursor behind decimalseparator
SelLength := Length(Text); // and select decimal part of string
end;
key:=#0;
end else // If '-' then first check position at front
if (Key = '-') and (Selstart <> 0) then
begin
key:=#0;
beep;
end;
end;
|
DoExit / DoEnter
In this methods the rounding is done.
procedure TNumEdit.DoEnter; // Perform rounding when entering
begin
If AutoRounding then // Only when AutoRounding is enabled
if (Text <> '') and Round then
Text := RoundedText(Text);
end;
procedure TNumEdit.DoExit; // Perform rounding when exiting
begin
if (Text <> '') and Round then
Text := RoundedText(Text);
end;
|
Change
The change method takes care of rounding when a value is set in code. (KeyPressed false)
The rounding
Rounding is done with the procedure FmtStr.
Function TNumEdit.RoundedText(aText : String) : String; //Perform rounding the text begin FmtStr(Result,'%0.'+ IntToStr(RoundingDecimals) +'f',[StrToFLoat(Text)]); KeyPressed := false; end; |
Alignment
Numeric values are mostly right aligned.
A standard edit box doesn't offer a way to do alignment.
After struggling through the vcl I found out that a TMemo (is in fact a multiline edit)
can align the text which it contains.
I build this code in TNumEdit to enable alignment.
You have to publish a property alignment of type TAlignment and with the override
method
Createparams you can set the style you wish.
procedure TNumEdit.CreateParams(var Params: TCreateParams);
const
Alignments: array[Boolean, TAlignment] of DWORD =
((ES_LEFT, ES_RIGHT, ES_CENTER),(ES_RIGHT, ES_LEFT, ES_CENTER));// Windows parameters
begin
inherited CreateParams(Params);// Don't forget to inherit
with Params do
begin
Style := Style or ES_MULTILINE or
Alignments[UseRightToLeftAlignment, FAlignment];// Set the style for alignment
end;
end;
|
The complete source code of TNumEdit :
////////////////////////////////////////////////////////////////////////
// TNumEdit Control version 1.0 08-01-2000
// Input : 0..9, -(1x) and the DecimalSeparator (1x)
// This control can also round the value by #decimals
//
// (c) BeenSoft Http://surf.to/beensoft Mail : beensoft@yahoo.com
////////////////////////////////////////////////////////////////////////
unit NumEdit;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;
type
TNumEdit = class(TCustomEdit)
private
{ Private declarations }
FAutoRounding : Boolean;
FRound : Boolean; // Rounding
FRoundingDecimals : Integer; // Number of decimals for rounding
FKeyPressed : Boolean; // Keypressed
FAlignment : TAlignment;
Function RoundedText(aText : String) : String; // Perform the rounding
procedure KeyPress(var Key: Char); override;
procedure DoExit; override;
procedure DoEnter; override;
procedure Change; override;
public
{ Public declarations }
Constructor Create (AOwner : TComponent); override;
procedure CreateParams(var Params: TCreateParams); override;
procedure SetAlignment(Value: TAlignment);
property KeyPressed : boolean read FKeyPressed write FKeyPressed default False;
property Alignment: TAlignment read FAlignment write SetAlignment default taLeftJustify;
published
{ Published declarations }
//new properties
property AutoRounding : boolean read FAutoRounding write FAutoRounding default False;
property RoundingDecimals : Integer read FRoundingDecimals write FRoundingDecimals;
property Round : boolean read FRound write FRound default false;
//publishing properties declared in TCustomEdit
property Anchors;
property AutoSelect;
property AutoSize;
property BiDiMode;
property BorderStyle;
property CharCase;
property Color;
property Constraints;
property Ctl3D;
property DragCursor;
property DragKind;
property DragMode;
property Enabled;
property Font;
property HideSelection;
property ImeMode;
property ImeName;
property MaxLength;
property OEMConvert;
property ParentBiDiMode;
property ParentColor;
property ParentCtl3D;
property ParentFont;
property ParentShowHint;
property PasswordChar;
property PopupMenu;
property ReadOnly;
property ShowHint;
property TabOrder;
property TabStop;
property Text;
property Visible;
property OnChange;
property OnClick;
property OnDblClick;
property OnDragDrop;
property OnDragOver;
property OnEndDock;
property OnEndDrag;
property OnEnter;
property OnExit;
property OnKeyDown;
property OnKeyPress;
property OnKeyUp;
property OnMouseDown;
property OnMouseMove;
property OnMouseUp;
property OnStartDock;
property OnStartDrag;
end;
procedure Register;
implementation
Constructor TNumEdit.Create (AOwner : TComponent);
begin
Inherited Create(AOwner);
SetAlignment(taRightJustify);
Text := '0';
end;
procedure TNumEdit.CreateParams(var Params: TCreateParams);
const
Alignments: array[Boolean, TAlignment] of DWORD =
((ES_LEFT, ES_RIGHT, ES_CENTER),(ES_RIGHT, ES_LEFT, ES_CENTER));
begin
inherited CreateParams(Params);
with Params do
begin
Style := Style or ES_MULTILINE or
Alignments[UseRightToLeftAlignment, FAlignment];
end;
end;
procedure TNumEdit.SetAlignment(Value: TAlignment); //Set the Alignment
begin
if FAlignment <> Value then
begin
FAlignment := Value;
RecreateWnd; //Force a redraw of the control
end;
end;
Function TNumEdit.RoundedText(aText : String) : String; //Perform rounding the text
begin
FmtStr(Result,'%0.'+ IntToStr(RoundingDecimals) +'f',[StrToFLoat(Text)]);
KeyPressed := false;
end;
procedure TNumEdit.Change;
begin
if not KeyPressed then
begin
if (Text <> '') and Round then
Text := RoundedText(Text);
end
end;
procedure TNumEdit.DoEnter; // Perform rounding when entering
begin
If AutoRounding then
if (Text <> '') and Round then
Text := RoundedText(Text);
end;
procedure TNumEdit.DoExit; // Perform rounding when exiting
begin
if (Text <> '') and Round then
Text := RoundedText(Text);
end;
procedure TNumEdit.KeyPress(var Key: Char);
begin
KeyPressed := true;
Inherited KeyPress(Key); // For user events
//Check for Numeric and backspaces
if not (Key in ['0'..'9', '-', DecimalSeparator,#8]) then
begin
KeyPressed := False;
key:=#0;
beep;
end else //Check for existing ofdecimalsepatator and '-'
if ((Key = DecimalSeparator) or (key = '-')) and (Pos(Key, Text) > 0) then
begin
If Key = DecimalSeparator then
begin
SelStart := Pos(Key, Text);
SelLength := Length(Text);
end;
key:=#0;
end else // If '-' then first check position at front
if (Key = '-') and (Selstart <> 0) then
begin
key:=#0;
beep;
end;
end;
procedure Register;
begin
RegisterComponents('Beensoft', [TNumEdit]);
end;
end.
|