Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 8837941
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 14, 20262026-06-14T09:51:35+00:00 2026-06-14T09:51:35+00:00

The problem I’m wanting to solve is to display to the user the remaining

  • 0

The problem I’m wanting to solve is to display to the user the remaining characters left in a field as they are typing into a TDBEdit.

Currently I’m doing something along the lines of

lCharRemaining.Caption := Field.Size - length(dbedit.text);

i.e. updating a label in the OnChange event for the TDBEdit, which works perfectly fine. However I’m wanting to do this for a number of TDBEdits and tried to write a custom component that would display the length remaining within the edit box on the right. It however interferes with editing. I was perhaps thinking that I could display a hint while someone was typing indicating the remaining space in the field – any suggestions?

Here is the code for my component (if someone can suggest improvements).

unit DBEditWithLenghtCountdown;

interface

uses
  SysUtils, Classes, Controls, StdCtrls, Mask, DBCtrls, messages, Graphics;

type
  TDBEditWithLenghtCountdown = class(TDBEdit)
  private
    { Private declarations }
    FCanvas: TCanvas;
    procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
  protected
    { Protected declarations }
    property Canvas: TCanvas read FCanvas;
    procedure WndProc(var Message: TMessage); override;
  public
    { Public declarations }
    function CharactersRemaining : integer;
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    { Published declarations }
  end;

procedure Register;

implementation

uses
  db, Types;

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

{ TDBEditWithLenghtCountdown }

function TDBEditWithLenghtCountdown.CharactersRemaining: integer;
begin
  result := -1;
  if Assigned(Field)then
  begin
    result := Field.Size - Length(Text);
  end;
end;

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

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

procedure TDBEditWithLenghtCountdown.WMPaint(var Message: TWMPaint);
var
  R: TRect;
  Remaining : string;
  WidthOfText: Integer;
  x: Integer;
begin
  inherited;
  if not focused then
    exit;


  Remaining := IntToStr(CharactersRemaining);
  R := ClientRect;
  Inc(R.Left, 1);
  Inc(R.Top, 1);
  Canvas.Brush.Assign(Self.Brush);
  Canvas.Brush.Style := bsClear;
  Canvas.Font.Assign(Self.Font);
  Canvas.Font.Color := clRed;

  WidthOfText := Canvas.TextWidth(Remaining);
  x := R.right - WidthOfText - 4;
  Canvas.TextOut(x,2, Remaining);
end;

procedure TDBEditWithLenghtCountdown.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; // case
end;

end.
  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-14T09:51:37+00:00Added an answer on June 14, 2026 at 9:51 am

    You can test how it would look like without any text interference by setting the edit margins to leave space for the tip text. A quick test:

    type
      TDBEditWithLenghtCountdown = class(TDBEdit)
        ..
      protected
        procedure CreateWnd; override;
        property Canvas: TCanvas read FCanvas;
        ..
    
    
    procedure TDBEditWithLenghtCountdown.CreateWnd;
    var
      MaxWidth, Margins: Integer;
    begin
      inherited;
      MaxWidth := Canvas.TextWidth('WW');
      Margins := Perform(EM_GETMARGINS, 0, 0);
      Margins := MakeLong(HiWord(Margins), LoWord(Margins) + MaxWidth);
      Perform(EM_SETMARGINS, EC_LEFTMARGIN or EC_RIGHTMARGIN, Margins);
    end;
    

    Beyond this is personal opinion but I find this a bit confusing. What I would do is probably publish a status panel field on the derived edit, and output some text to it if it is assigned when the text of the edit control changes.

    edit: Here’s a somewhat extended version that should take care of the issue mentioned in the comment (if navigate left with a long text, edit text overwrites tip text), and also sets margins only if the control has focus. (Not full code duplicated from the question, only modified bits.)

    type
      TDBEditWithLenghtCountdown = class(TDBEdit)
      private
        FCanvas: TCanvas;
        FTipWidth: Integer;
        FDefMargins: Integer;
        procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
      protected
        ..
    
    
    procedure TDBEditWithLenghtCountdown.WMPaint(var Message: TWMPaint);
    var
      PaintStruct: TPaintStruct;
      EndPaint: Boolean;
      Rgn: HRGN;
      R, TipR: TRect;
      Remaining : string;
    begin
      if not Focused then
        inherited
      else begin
        EndPaint := Message.Dc = 0;
        if Message.DC = 0 then
          Message.DC := BeginPaint(Handle, PaintStruct);
    
        R := ClientRect;
        TipR := R;
        TipR.Left := TipR.Right - FTipWidth;
        Remaining := IntToStr(CharactersRemaining);
        Canvas.Handle := Message.DC;
        SetBkColor(Canvas.Handle, ColorToRGB(Color));
        Canvas.Font := Font;
        Canvas.Font.Color :=  clRed;
        Canvas.TextRect(TipR, Remaining, [tfSingleLine, tfCenter, tfVerticalCenter]);
    
        R.Right := TipR.Left;
        Rgn := CreateRectRgn(R.Left, R.Top, R.Right, R.Bottom);
        SelectClipRgn(Canvas.Handle, Rgn);
        DeleteObject(Rgn);
        inherited;
        if EndPaint then
          windows.EndPaint(Handle, PaintStruct);
      end;
    end;
    
    procedure TDBEditWithLenghtCountdown.WndProc(var Message: TMessage);
    const
      TipMargin = 3;
    begin
      inherited WndProc(Message);
      with Message do
        case Msg of
          CM_MOUSEENTER, CM_MOUSELEAVE, WM_LBUTTONUP, WM_LBUTTONDOWN,
          WM_KEYDOWN, WM_KEYUP,
          CM_TEXTCHANGED: Invalidate;
          WM_CREATE: FDefMargins := Perform(EM_GETMARGINS, 0, 0);
          CM_FONTCHANGED:
            begin
              Canvas.Handle := 0;
              Canvas.Font := Font;
              FTipWidth := Canvas.TextWidth('67') + 2 * TipMargin;
            end;
          WM_SETFOCUS:
            Perform(EM_SETMARGINS, EC_LEFTMARGIN or EC_RIGHTMARGIN,
                MakeLong(HiWord(FDefMargins), LoWord(FDefMargins) + FTipWidth));
          WM_KILLFOCUS:
            Perform(EM_SETMARGINS, EC_LEFTMARGIN or EC_RIGHTMARGIN, FDefMargins);
        end;
    end;
    
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

Problem: If user is not logged into GameCenter account - GameCenter authentication view is
I am currently running into a problem where an element is coming back from
Problem occured when i tried to display xml data that has been taken by
Problem: Visitors open the url website.com/?i=133r534|213213|12312312 but this url isn't valid anymore and they
Problem: I have an address field from an Access database which has been converted
I ran into a problem. Wrote the following code snippet: teksti = teksti.Trim() teksti
Problem: user made some selection in the multi-selection listbox, then pressed a checkbox, and
Problem: When adding list item the Value field is being set to the Text
Problem: The user can choose how long and when start to track your locaton
Problem: Been struggling to get my code to load external shaders and it is

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.