Solved

TEdit - Creating a Custom TEdit Component with Text Indent

Posted on 2013-06-11
3
2,051 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
[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
  • 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

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

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

Suggested Solutions

This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
With Secure Portal Encryption, the recipient is sent a link to their email address directing them to the email laundry delivery page. From there, the recipient will be required to enter a user name and password to enter the page. Once the recipient …

734 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