Want to win a PS4? Go Premium and enter to win our High-Tech Treats giveaway. Enter to Win

x
?
Solved

TEdit - Creating a Custom TEdit Component with Text Indent

Posted on 2013-06-11
3
Medium Priority
?
2,211 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 23

Accepted Solution

by:
Ferruccio Accalai earned 2000 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 23

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

Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

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

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…
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…
In this video you will find out how to export Office 365 mailboxes using the built in eDiscovery tool. Bear in mind that although this method might be useful in some cases, using PST files as Office 365 backup is troublesome in a long run (more on t…
Are you ready to place your question in front of subject-matter experts for more timely responses? With the release of Priority Question, Premium Members, Team Accounts and Qualified Experts can now identify the emergent level of their issue, signal…
Suggested Courses

604 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