Tutorial : Het maken van een numeriek edit control
Download de source van dit component hier :
type
TNumEdit = class(TCustomEdit)
private
{ Private declarations }
public
{ Public declarations }
published
{ Published declarations }
end;
|
1. Wat is de bedoeling van het component TNumEdit
TNumEdit is een edit control die alleen numerieke waarden toestaat.
Naast numerieke waarden kan ook het decimal teken(1x) en het min teken(1x) ingevoerd
worden.
De invoer van de numerieke waarden is vrij, d.w.z dat er in eerste instantie geen format
opgelegd wordt
in de vorm van bijvoorbeeld het aantal decimalen.
Het component biedt echter wel de mogelijkheid om de ingevoerde waarde af te ronden op een
opgegeven
aantal decimalen. De formattering (afronden) van het getal wordt gedaan in de method
DoExit.
Wanneer de formattering in de Change method zou plaatsvinden zou dit ongewenst gedrag
geven omdat dan
bij elke toetsaanslag de formattering zou plaatsvinden waarbij de cursor positie
verplaatst. De Change method is echter wel toegevoegd om
waarden die middels code in de NumEdit box worden aangeboden automatisch te af te ronden.
2.Gebruikte technieken
Nieuwe published properties
Naast de ge-erfde properties van TCustomEdit zijn er een aantal nieuwe gepubliceerd te
weten :
Alle properties kunnen zowel in design- als runtime geset worden.
Override methods
De volgende methods zijn 'override' van de basisclasse TCustomEdit :
KeyPress
De property keypressed skipped het onchange event.
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 [#8, '0'..'9', '-', DecimalSeparator]) 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 deze methods wordt het afronden aangestuurd.
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
De change method verzorgt de afronding als er geen toets is ingedrukt (KeyPressed false)
De afronding van de waarde
Het afronden wordt gerealiseerd middels de 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
Numerieke waarden worden meestal rechts uitgelijnd.
Het probleem met een edit box is dat deze standaard geen mogelijkheid biedt om de
Alignment in te stellen.
Na enig doorworstelen van de vcl vond ik dat bijv. TMemo (is in feite een multiline edit)
wel deze mogelijkheid biedt.
Aan de hand van deze code heb ik e.e.a in TNumEdit gebouwd.
In het kort komt het er op neer dat het component een published alignment property moet
hebben van het type TAlignment.
Middels de override method createparams kan de gewenste style toegevoegd worden :
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;
|
De volledige code NumEdit.Pas ziet er als volgt uit :
////////////////////////////////////////////////////////////////////////
// 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 [#8, '0'..'9', '-', DecimalSeparator]) 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.
|