2

I am trying to create a set of custom components like TEdit, TDBEdit, TComboBox with a new kind of border (rounded corner) and I have created this code:

unit RoundRectControls;

interface

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

type
  TRoundRectEdit = class(TEdit)
  private
    { Private declarations }
  protected
    { Protected declarations }
  public
    constructor Create(AOwner: TComponent); override;
    { Public declarations }
  published
    property BorderStyle default bsNone;
    property Ctl3D default False;
    { Published declarations }
  end;

procedure Register;
procedure DrawRoundedRect(Control: TWinControl);

implementation

constructor TRoundRectEdit.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  DrawRoundedRect(Self);
end;

procedure Register;
begin
  RegisterComponents('Eduardo', [TRoundRectEdit]);
end;

procedure DrawRoundedRect(Control: TWinControl);
var
   r: TRect;
   Rgn: HRGN;
begin
   with Control do
   begin
     r := ClientRect;
     rgn := CreateRoundRectRgn(r.Left, r.Top, r.Right, r.Bottom, 30, 30) ;
     Perform(EM_GETRECT, 0, lParam(@r)) ;
     InflateRect(r, - 4, - 4) ;
     Perform(EM_SETRECTNP, 0, lParam(@r)) ;
     SetWindowRgn(Handle, rgn, True) ;
     Invalidate;
   end;
end;

end.

But after I tried to put the component in the Form, this message came:

Control '' has no Parent

So, how to I fix that? I am new to construct components and I need a good tutorial on the web. Something tells me that I need to make that DrawRoundedRect outside the Constructor... But where?

Edit 1 - 2012-07-27 14:50

Result

Sertac Akyuz's Answer was great and resolved the problem, but the result was kind of ugly. I don't know what I am doing wrong. The text of the EditBox is too close to the top-left. Does anyone know how do I fix it?

NaN
  • 8,596
  • 20
  • 79
  • 153
  • 1
    Re: your edit - Your `EM_SETRECTNP` call is probably ignored since EM_SETRECT/EM_SETRECTNP is for multiline edit controls. Might have better luck with `EM_SETMARGINS`. – Sertac Akyuz Jul 27 '12 at 18:02
  • It did not change anything at the UI :-( – NaN Jul 27 '12 at 19:53
  • EM_SETMARGINS work ok here. But I can't really say it looks good, for one thing, the shadow lines around the curves look terrible, second, there's no vertical alignment. Alternatively you can make your edit multiline (override CreateParams and add ES_MULTILINE style) and then handle to intercept VK_RETURN etc.. – Sertac Akyuz Jul 27 '12 at 20:29

2 Answers2

5

You are requesting 'ClientRect' but the edit control window has not been created yet (no window, no rectangle). You can move your region modifying code to some place after it is created. Example:

type
  TRoundRectEdit = class(TEdit)
  private
    { Private declarations }
  protected
    procedure CreateWnd; override;
    { Protected declarations }
  public
    constructor Create(AOwner: TComponent); override;
    ...

constructor TRoundRectEdit.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
//  DrawRoundedRect(Self);
end;

procedure TRoundRectEdit.CreateWnd;
begin
  inherited;
  DrawRoundedRect(Self);
end;


The error message itself reflects the effort of the VCL to create the window once its handle has been requested. It can't do so because it cannot resolve in what window the control is to be placed.

Sertac Akyuz
  • 54,131
  • 4
  • 102
  • 169
  • 1
    +1, @EASI, you might see the answer in your previous question ;-) – TLama Jul 27 '12 at 17:30
  • Just a shortlink to that question: [How do we make rounded corner TFrame?](http://stackoverflow.com/q/11675374/576719). – LU RD Jul 27 '12 at 18:00
  • 1
    You also need to resize the region every time the control is resized. Creating a fixed-size region in `CreateWnd()` alone is not enough. – Remy Lebeau Jul 27 '12 at 18:05
1

Creating a new region in SetBounds() should be fine. Just be sure to call inherited first, and then use the updated Width/Height to create the new region. CreateWnd() should still create the initial region using the current Width/Height. SetBounds() should recreate the region only if HandleAllocated() is True.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770