Search code examples
delphidelphi-7

Setting CustomComponent(TEDIT) MaxLength Property not working


I have created a new component which is derived from TEdit. In the below code, I am setting MaxLength Property to 10 after setting AllowValues to true.

I set the component on form and set the AllowValues to true and run the application and edit box is allowing more than 10 characters. whats wrong with my code?

unit DummyEdit;

interface

uses
  SysUtils, Classes, Controls, StdCtrls,Dialogs,Windows,Messages;

type
  TDUMMYEdit = class(TEdit)
  private
    { Private declarations }
    FAllowValues : Boolean;
    FMaxLength: Integer;
    Procedure SetAllowValues(Value : Boolean);
    procedure SetMaxLength(Value: Integer);
  protected
    { Protected declarations }
  public
    { Public declarations }
  published
    { Published declarations }
    Property AllowValues : Boolean read FAllowValues write SetAllowValues;
    property MaxLength: Integer read FMaxLength write SetMaxLength default 0;
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('DUMMY', [TDUMMYEdit]);
end;

{ TDUMMYEdit }


procedure TDUMMYEdit.SetAllowValues(Value: Boolean);
begin
  if FAllowValues <> value then
    FAllowValues := Value;
  if FAllowValues then
    MaxLength := 10
  else
    MaxLength := 0;    
end;

procedure TDUMMYEdit.SetMaxLength(Value: Integer);
begin
  if FMaxLength <> Value then
  begin
    FMaxLength := Value;
    if HandleAllocated then SendMessage(Handle, EM_LIMITTEXT, Value, 0);
  end;
end;

end.

Solution

  • Working on an answer I realized that you re-invented the MaxLength property for your custom edit. Was that your intention? Unless I'm mistaken all that currently differs is that you accidentally introduced the bug that is topic of this question. Your code should work if you hadn't introduced that property.

    So one way to solve your issue is to remove the MaxLength property from TDUMMYEdit, instead rely on the one TCustomEdit implements.

    Your issue is that when your code takes effect during component streaming from DFM, no Handle is allocated, HandleAllocated returns False and your EM_LIMITTEXT message will not be sent. Setting the AllowValues property later on, e.g. in an event handler of your form, would work as you'd expect, as at that time, a handle is allocated.

    A way to fix this can be found looking atTCustomEdit in Vcl.StdCtrls - code you might have taken as example, it looks very similar - the procedure DoSetMaxLength - which will send the same message you are trying to send - will also be called in TCustomEdit.CreateWnd, at a time where there is a valid Handle created. A fix for your code would then look like this:

      TDUMMYEdit = class(TEdit)
      private
        { Private declarations }
        FAllowValues : Boolean;
        FMaxLength: Integer;
        Procedure SetAllowValues(Value : Boolean);
        procedure SetMaxLength(Value: Integer);
      protected
        { Protected declarations }
        procedure CreateWnd; override;    
      public
        { Public declarations }
      published
        { Published declarations }
        Property AllowValues : Boolean read FAllowValues write SetAllowValues;
        property MaxLength: Integer read FMaxLength write SetMaxLength default 0;
      end;
    
    procedure Register;
    
    implementation
    
    procedure Register;
    begin
      RegisterComponents('DUMMY', [TDUMMYEdit]);
    end;
    
    { TDUMMYEdit }
    
    ...
    procedure TDUMMYEdit.CreateWnd;
    begin
      inherited CreateWnd;
      SendMessage(Handle, EM_LIMITTEXT, FMaxLength, 0);
    end;
    ...