¿Cómo dibujar cosas adicionales en un componente personalizado después de la creación en DT/RT?

Estoy tratando de crear un conjunto de componentes personalizados como TEdit, TDBEdit, TComboBox con un nuevo tipo de borde (esquina redondeada) y he creado este código:

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.

Pero después de que intenté poner el componente en el Formulario, apareció este mensaje:

Control '' no tiene padre

Entonces, ¿cómo arreglo eso? Soy nuevo en la construcción de componentes y necesito un buen tutorial en la web. Algo me dice que tengo que hacer eso DrawRoundedRect fuera del Constructor... Pero, ¿dónde?

Editar 1 - 2012-07-27 14:50

Resultado

La respuesta de Sertac Akyuz fue excelente y resolvió el problema, pero el resultado fue un poco feo. No sé qué estoy haciendo mal. El texto del EditBox está demasiado cerca de la esquina superior izquierda. ¿Alguien sabe cómo lo arreglo?

preguntado el 27 de julio de 12 a las 17:07

Re: tu edición - Tu EM_SETRECTNP probablemente se ignore la llamada ya que EM_SETRECT/EM_SETRECTNP es para controles de edición multilínea. Podría tener mejor suerte con EM_SETMARGINS. -

No cambió nada en la interfaz de usuario :-( -

EM_SETMARGINS funciona bien aquí. Pero realmente no puedo decir que se vea bien, primero, las líneas de sombra alrededor de las curvas se ven terribles, segundo, no hay alineación vertical. Alternativamente, puede hacer su edición multilínea (anular CreateParams y agregar el estilo ES_MULTILINE) y luego manejar para interceptar VK_RETURN, etc. -

2 Respuestas

Está solicitando 'ClientRect' pero la ventana de control de edición aún no se ha creado (sin ventana, sin rectángulo). Puede mover el código de modificación de su región a algún lugar después de crearlo. Ejemplo:

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;


El mensaje de error en sí refleja el esfuerzo de la VCL para crear la ventana una vez que se ha solicitado su identificador. No puede hacerlo porque no puede resolver en qué ventana se debe colocar el control.

Respondido 27 Jul 12, 18:07

+1, @EASI, es posible que vea la respuesta en su pregunta anterior ;-) - TLama

Solo un enlace corto a esa pregunta: ¿Cómo hacemos TFrame de esquina redondeada?. - LU RD

También debe cambiar el tamaño de la región cada vez que se cambia el tamaño del control. Creación de una región de tamaño fijo en CreateWnd() solo no es suficiente. - Rémy Lebeau

Crear una nueva región en SetBounds() debería estar bien. Solo asegúrate de llamar inherited primero, y luego use el actualizado Width/Height para crear la nueva región. CreateWnd() todavía debe crear la región inicial usando el actual Width/Height. SetBounds() debe recrear la región sólo si HandleAllocated() es verdad.

Respondido 27 Jul 12, 19:07

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.