Solved

TEdit - Creating a Custom TEdit Component with Text Indent

Posted on 2013-06-11
3
1,924 Views
Last Modified: 2013-06-12
Hi,

I'm trying to create my own Delphi TEdit Component that will allow me to indent the text in the Text Field from the left (Not using spaces) by a certain number of pixels. This number will be specified in a Property called Indent but I also want to keep all the other visual and formatting features provided but TEdit.

I have managed to compile and install my own component using the code below with mixed results. In the most part this component works, but I lose all the other visual elements and formatting that the base TEdit component provides.

For example, I can no longer get the black border to show around the textbox when I set the Ctrl3D property to false, I can't highlight text or do any other type of text formatting.

If I remove the Paint procedure or comment out the FillRect(ClientRect) line, the component's visual formatting works but the text is painted incorrectly and the cursor is a few pixels behind the end of the line. Do I need to inherit the edit properties from TEdit before re-painting the component?

I'm new to component building and may have coded this all wrong so sorry for the code I've assembled, I've based most of it from what I've managed to read from the internet.

Thanks for your help.


unit TNewEdit;

interface

uses
  System.SysUtils, System.Classes, Vcl.Controls, Vcl.StdCtrls, Vcl.Graphics,
  System.Types, Winapi.Windows, Winapi.Messages;

type
  TMyEdit = class(TEdit)
  private
    { Private declarations }
    FIndent : integer;
    FCanvas : TCanvas;
    procedure SetIndent(const Value:integer);
    procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
  protected
    { Protected declarations }
    procedure Paint; virtual;
    procedure WndProc(var Message: TMessage); override;
    procedure PaintWindow(DC: HDC); override;
    property Canvas: TCanvas read FCanvas;
  public
    { Public declarations }
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    { Published declarations }
    property Indent: Integer read FIndent write SetIndent default 3;
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('My Components', [TMyEdit]);
end;

constructor TMyEdit.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FCanvas := TControlCanvas.Create;
  TControlCanvas(FCanvas).Control := Self;
  FIndent:=3;
end;

destructor TMyEdit.Destroy;
begin
  FCanvas.Free;
  inherited Destroy;
end;

procedure TMyEdit.Paint;
var
  IRec: TRect;
begin
  inherited;

  IRec := ClientRect;
  IRec.Left := IRec.Left + FIndent;
  IRec.Top  := IRec.Top + 2;

  FCanvas.FillRect(ClientRect);
  FCanvas.Brush.Assign(Self.Brush);
  FCanvas.Font.Assign(Self.Font);

  DrawText(FCanvas.Handle, Self.Text, Length(Self.Text), IRec, DT_LEFT);

end;

procedure TMyEdit.SetIndent(const Value: Integer);
begin
  if FIndent <> Value then
   begin
     FIndent := Value;
     Invalidate;
   end;
end;

procedure TMyEdit.PaintWindow(DC: HDC);
begin
  inherited;
  FCanvas.Lock;
  try
   FCanvas.Handle := DC;
   try
     TControlCanvas(FCanvas).UpdateTextFlags;
     Paint;
   finally
     FCanvas.Handle := 0;
   end;
  finally
   FCanvas.Unlock;
  end;
end;

procedure TMyEdit.WMPaint(var Message: TWMPaint);
begin
  ControlState := ControlState+[csCustomPaint];
  inherited;
  ControlState := ControlState-[csCustomPaint];
end;

procedure TMyEdit.WndProc(var Message: TMessage);
begin
 inherited WndProc(Message);
  with Message do
    case Msg of
      CM_MOUSEENTER, CM_MOUSELEAVE, WM_LBUTTONUP, WM_LBUTTONDOWN,
      WM_KEYDOWN, WM_KEYUP,
      WM_SETFOCUS, WM_KILLFOCUS,
      CM_FONTCHANGED, CM_TEXTCHANGED:
      begin
        Invalidate;
      end;
   end; 
end;

end.

Open in new window

0
Comment
Question by:PlantEric
  • 2
3 Comments
 
LVL 22

Accepted Solution

by:
Ferruccio Accalai earned 500 total points
ID: 39240816
Why don't you simply set the left margin? All your code is not needed, you should simply send a message to change the left margin of the Tedit control

Take a look at this example

unit MyEdit;

interface

uses
  SysUtils, Classes, Controls, StdCtrls, windows, messages;

type
  TMyEdit = class(TEdit)
  private
    { Private declarations }
    fIndent: Integer;
    procedure SetIndent(value: Integer);
  protected
    { Protected declarations }
  public
    { Public declarations }
  published
    { Published declarations }
    property Indent: Integer read fIndent write SetIndent;
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Samples', [TMyEdit]);
end;

procedure TMyEdit.SetIndent(value: Integer);
begin
  if fIndent <> value then
  begin
    fIndent := value;
    // her we use EC_USEFONTINFO accordin to what explained by msdn at http://msdn.microsoft.com/en-us/library/bb761649%28VS.85%29.aspx
    SendMessage(self.Handle, EM_SETMARGINS, EC_USEFONTINFO, value);
  end;
end;

end.

Open in new window

0
 

Author Closing Comment

by:PlantEric
ID: 39241495
Great solution thanks!

Only thing is, when re-loading the project in Delphi it doesn't show the margin at design time only when running, unless I change the indent at design time but then goes back when re-loaded.

Many thanks.
0
 
LVL 22

Expert Comment

by:Ferruccio Accalai
ID: 39241893
@when re-loading the project in Delphi it doesn't show the margin at design time

As in my simple sample everything works fine, I guess that it could depend on something in your component constructor. Can you show me how at the end have you coded your component?
0

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

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

Suggested Solutions

Objective: - This article will help user in how to convert their numeric value become words. How to use 1. You can copy this code in your Unit as function 2. than you can perform your function by type this code The Code   (CODE) The Im…
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…
Windows 10 is mostly good. However the one thing that annoys me is how many clicks you have to do to dial a VPN connection. You have to go to settings from the start menu, (2 clicks), Network and Internet (1 click), Click VPN (another click) then fi…
Migrating to Microsoft Office 365 is becoming increasingly popular for organizations both large and small. If you have made the leap to Microsoft’s cloud platform, you know that you will need to create a corporate email signature for your Office 365…

896 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

Need Help in Real-Time?

Connect with top rated Experts

16 Experts available now in Live!

Get 1:1 Help Now