Delphi Clinic C++Builder Gate Training & Consultancy Delphi Notes Weblog Dr.Bob's Webshop
Bob Swart (aka Dr.Bob) - Medical Officer Delphi 6 Developer's Guide
 Dr.Bob's Tip-Of-The-Hat #6
See Also: Delphi Papers, Columns and other Tip-Of-The-Hats

Right-Aligned TB42Edit
The TEdit component in Delphi is based on the Windows editbox control - a small but powerful control that has its roots in the first versions of Windows. A big brother of the TEdit component is the TMemo component: a multi-line editbox.
Apart from the fact that an editbox is a single line and a memo can contain multiple lines, there is one other major difference: a TMemo component can be right-aligned (or center or left), while a TEdit component can only be left-aligned. This sure is a nuisance when the user has to enter a sequence of numerical values, which are hard to read if not aligned to the right.
Fortunately, we can workaround this problem by starting from the shared ancestor class TCustomEdit and work down towards a right-aligned single-line editbox called TB42Edit. Because we derived TB42Edit from TCustomMemo, there are no published properties, yet (but only public properties), so we must publish all properties we want to be part of our TB42Edit component:

  unit Edit42;
  interface
  uses
    Classes, Controls, StdCtrls;

  type
    TB42Edit = class(TCustomMemo)
    public
      { Public declarations }
      constructor Create(AOwner: TComponent); override;
      procedure SetBounds(ALeft, ATop, AWidth, AHeight: Integer); override;
      procedure KeyDown(var Key: Word; Shift: TShiftState); override;
      procedure KeyPress(var Key: Char); override;
      procedure Change; override;
    published
      { Published declarations }
      property BorderStyle;
      property CharCase;
      property Color;
      property Ctl3D;
      property Cursor;
      property DragCursor;
      property DragMode;
      property Enabled;
      property Font;
      property Height;
      property HelpContext;
      property HideSelection;
      property Hint;
      property Left;
      property MaxLength;
      property Name;
      property OEMConvert;
      property ParentColor;
      property ParentCtl3D;
      property ParentFont;
      property ParentShowHint;
      property PopupMenu;
      property ReadOnly;
      property ShowHint;
      property TabOrder;
      property Tag;
      property Text;
      property Top;
      property Visible;
      property Width;

      property OnChange;
      property OnClick;
      property OnDblClick;
      property OnDragDrop;
      property OnDragOver;
      property OnEndDrag;
      property OnEnter;
      property OnExit;
      property OnKeyDown;
      property OnKeyPress;
      property OnKeyUp;
      property OnMouseDown;
      property OnMouseMove;
      property OnMouseUp;
    end;

Constructor
The implementation consists of six parts. First of all, we have the constructor, in which we need to set the (unpublished) Alignment property to taRightJustify. We should also initialize the ScrollBars (to ssNone), and set the WantReturns, WantTabs and WordWrap properties to False;

  constructor TB42Edit.Create(AOwner: TComponent);
  begin
    inherited Create(AOwner);
    Align := alNone;
    Alignment := taRightJustify;
    ScrollBars := ssNone;
    WantReturns := False;
    WantTabs := False;
    WordWrap := False;
  end;

SetBounds
The SetBounds method is the one that makes sure that our TB42Edit component appears as a single-line editbox, no matter what. It can be compared to the TSizeConstraints of Delphi5, but SetBounds works in all versions of Delphi:

  procedure TB42Edit.SetBounds(ALeft, ATop, AWidth, AHeight: Integer);
  begin
    if AHeight > (2 * abs(Font.Height)) then
      AHeight := 2 * abs(Font.Height);
    inherited SetBounds(ALeft, ATop, AWidth, AHeight);
  end;

No carriage return or linefeeds
Apart from appearing as single-line editbox, we must also make sure that the user cannot type a carriage return or line feed inside the control. This is done by overriding the KeyDown and/or the KeyPress event handlers.

  procedure TB42Edit.KeyDown(var Key: Word; Shift: TShiftState);
  begin
    if Key in [10, 13] then Key := 0
    else
      inherited KeyDown(Key, Shift)
  end;

  procedure TB42Edit.KeyPress(var Key: Char);
  begin
    if Key in [#10, #13] then Key := #0
    else
      inherited KeyPress(Key)
  end;

Epilogue
Even if the user cannot type a #10 or #13 character, it may still be possible to paste one inside the control, so as catch-all we should also override the Change event:

  procedure TB42Edit.Change;
  var
    MyText: String;
    CrPos: integer;
  begin
    MyText := Text;
    CrPos := Pos(#13, MyText);
    if CrPos > 0 then Text := Copy(MyText, 1, CrPos-1)
    else
      inherited Change
  end;
This will make sure that all text after a #13 will be removed!


This webpage © 2001-2009 by Bob Swart (aka Dr.Bob - www.drbob42.com). All Rights Reserved.