I created a simple little unit that gives the basic TEdit
component the ability to display a colorizable border. Essentially, it is:
type
TEdit = class(StdCtrls.TEdit)
private
FBorderColor: TColor;
FUseCustomColor: boolean;
procedure SetUseCustomColor(const Value: boolean);
procedure SetBorderColor(const Value: TColor);
procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
public
property BorderColor: TColor read FBorderColor write SetBorderColor;
property UseCustomColor: boolean read FUseCustomColor write SetUseCustomColor;
end;
implementation
procedure TEdit.SetBorderColor(const Value: TColor);
begin
if FBorderColor <> Value then
begin
FBorderColor := Value;
Self.Repaint;
end;
end;
procedure TEdit.SetUseCustomColor(const Value: boolean);
begin
if FUseCustomColor <> Value then
begin
FUseCustomColor := Value;
Self.Repaint;
end;
end;
procedure TEdit.WMPaint(var Message: TWMPaint);
var
CC: TControlCanvas;
begin
inherited;
if FUseCustomColor then
begin
CC := TControlCanvas.Create;
try
CC.Control := Self;
CC.Pen.Color := FBorderColor;
CC.Pen.Width := 1;
CC.Brush.Style := bsClear;
CC.Rectangle(ClientRect);
finally
CC.Free;
end;
end;
end;
There is no problem with the TEdit
on the form, but I have a special TEdit
that adds extra functionality to the basic TEdit
(password masking, when initialized it displays a random length text so that when opened it is not possible to deduce the password from the length of the password).
I replace the component with the following function:
type
TPasswordEdit = class(TEdit)
private
FInitialText: string;
procedure UpdatePasswordChar;
function GetIsInitial: boolean;
protected
procedure CMFontChanged(var Msg: TMessage); message CM_FONTCHANGED;
public
constructor Create(AOwner: TComponent); override;
procedure InitializeText(const bIsEmpty: boolean);
procedure InitializeTextAgainst(const PasswordEdit: TPasswordEdit);
property IsInitial: boolean read GetIsInitial;
class function ReplaceEdit(const Replaced: TCustomEdit): TPasswordEdit;
class function IsComplexPassword(const strPassword: WideString;
const intMinLength: integer): boolean;
end;
implementation
class function TPasswordEdit.ReplaceEdit(
const Replaced: TCustomEdit): TPasswordEdit;
var
intTabOrder: integer;
i: integer;
begin
intTabOrder := Replaced.TabOrder;
Result := TPasswordEdit.Create(Replaced.Owner);
try
Result.Parent := Replaced.Parent;
{ copy relevant visual properties }
Result.SetBounds(
Replaced.Left, Replaced.Top, Replaced.Width, Replaced.Height);
Result.Anchors := Replaced.Anchors;
Result.TabOrder := intTabOrder;
if Replaced is TEdit then
begin
Result.Font := (Replaced as TEdit).Font;
Result.ParentFont := (Replaced as TEdit).ParentFont;
Result.Color := (Replaced as TEdit).Color;
end
else
raise Exception.Create(
'Unsupported TCustomEdit to be replaced with a TPasswordEdit.');
{ change relevant references }
for i := 0 to Replaced.Owner.ComponentCount - 1 do
if Replaced.Owner.Components[i] is TLabel then
if (Replaced.Owner.Components[i] as TLabel).FocusControl = Replaced then
(Replaced.Owner.Components[i] as TLabel).FocusControl := Result;
Replaced.Hide;
except
Result.Free;
raise;
end;
end;
The problem is that the WM_PAINT
event is not called on such a replaced component. Of course I created the TPasswordEdit
class inside the first unit with the same functionality.
One more additive... The development environment is Delphi 7, and due to the huge size of the whole project, it is not possible to port it to newer Delphi.
Anyone have any ideas?
As I read it, WM_PAINT
needs the Form message handler to know about it, and from the descriptions, Invalidate
was recommended everywhere. I tried InvalidateWindow
, Form Invalidate
and called it on the new component, but no way the message handler was called.
I changed the SetBorderColor()
and SetUseCustomColor()
functions to call the WMPaint()
function and the border appears, but as soon as I drag the window out and then back in, the repaint does not happen.