![]() |
![]() |
| Paypal | FTP | CCD | Buscar | Trucos | Trabajo | Foros |
|
|||||||
| Registrarse | FAQ | Miembros | Calendario | Guía de estilo | Temas de Hoy |
|
|
Herramientas | Buscar en Tema | Desplegado |
|
#24
|
||||
|
||||
|
Hola,
Antes de decirles de dónde ha salido el código de TDoublePanel déjenme explicarles según como ahora entiendo lo que pasa. Partamos de la idea original de CAOS, en la que simplemente crea los dos subpáneles (TopPanel y ClientPanel) en el constructor de la componente y vayamos viendo qué sucede. Cuando recién insertamos la componente los subpáneles se muestran correctamente y podemos insertarles controles. El problema, como ya hizo notar jmariano, es que el IDE, al momento de escribir el dfm, no se entera de la existencia de los controles insertados porque no están en ningún control que reconozca. De hecho el IDE ni squiera sabe que TopPanel y ClientPanel está ahí, como puede verse en el dfm que crea: Código:
object Form1: TForm1
Left = 192
Top = 161
Width = 870
Height = 500
Caption = 'Form1'
...
object DoublePanel1: TDoublePanel
Left = 16
Top = 16
Width = 377
Height = 249
BevelOuter = bvLowered
Caption = 'DoublePanel1'
TabOrder = 0
end
end
La primera respuesta es que el IDE simplemente se fija si una componente es un descendiente de TWinControl (el primero en la jerarquía capaz de almacenar controles) y guarda todos los controles que estén contenidos en él. Pero resulta que esto es incorrecto. Lo cierto es que cada componente (TWinControl o no) debe indicarle al IDE cuáles controles son sus 'hijos'. Pero para el IDE 'hijo' es un concepto independiente de la relación TControl.Parent y TWinControl.Controls. Para indicar al IDE cuáles componentes debe tratar como hijos se usa el método GetChildren. TWinControl define implemente GetChildren así:
Es decir, simplemente le dice al IDE con Proc(Control) que considere como hijos a los controles de su lista Controls. Entonces, en nuestra componente redefinimos GetChildren para decirle al IDE que considere hijos directos a los controles que hayan sido insertados en los subpáneles. Con ello el IDE genera un dfm así: Código:
object Form1: TForm1
Left = 192
Top = 161
Width = 870
Height = 500
Caption = 'Form1'
...
object DoublePanel1: TDoublePanel
Left = 8
Top = 8
Width = 377
Height = 249
BevelOuter = bvLowered
Caption = 'DoublePanel1'
TabOrder = 0
object Edit1: TEdit
Left = 8
Top = 8
Width = 121
Height = 21
TabOrder = 0
Text = 'Edit1'
end
object Button1: TButton
Left = 288
Top = 8
Width = 75
Height = 25
Caption = 'Button1'
TabOrder = 1
end
object Memo1: TMemo
Left = 8
Top = 8
Width = 185
Height = 89
Lines.Strings = (
'Memo1')
TabOrder = 0
end
end
end
Al indicarle al IDE que los controles insertados en cada suppánel son hijos de DoublePanel, estos controles quedan escritos como si los hubiéramos insertado directamente en él. Hasta aquí todo va bien en tanto que los controles insertados se han guardado en el dfm. Pero claro, el problema está en que al regresar a ver el formulario el IDE hace exactamente lo que se supone que debe hacer: construye un formulario con un hijo directo (DoublePanel) que a su vez tiene como hijos directos los controles insertados, es decir, estos últimos ya no viven dentro de los subpáneles. Los subpáneles existen porque se crean en el constructor de la componente y los controles insertados existen porque se leen del dfm. Es sólo que no están donde deben estar. Entonces, lo que debemos hacer es reinsertar los controles en sus respectivos contenedores (los subpáneles). No debemos crearlos otra vez porque ya el IDE lo hizo, sólo debemos cambiarles su propiedad Parent. ¿Cuándo se hace esto? Pues cuando ya se hayan leído completamente desde el dfm, es decir, en el método Loaded. Pero, ¿cómo sabemos cuál control va dentro de cuál subpánel? Recordemos que ahora todos se ven como hijos directos de nuestra componente así que no sabemos en cuál meterlos. De hecho, si no les digo donde yo había puesto Edit1, Button1 y Memo1, ustedes no lo sabrían. Aquí es donde DefineProperties es crucial. DefineProperties es un método que nos sirve para guardar valores cualesquiera en el dfm. El método usa Filer.DefineProperty para indicar cuál método se usa para escribir los valores al dfm y cuál se usa para leer de vuelta los valores. El primer parámetro de DefineProperty es el nombre del identificador de la 'propiedad' que deseamos guardar. Mi error fue nombrarlos igual que los subpáneles y por ello mismo no entendía ayer del todo lo que pasaba pues pensaba que se refería a ellos. Cambien esos nombres por, por ejemplo, 'TopPanelControlNames' y 'ClientPanelControlNames' para dejar más en claro lo que realmente estamos guardando en el dfm: los nombres de los controles insertados. Al hacer esto, el dfm queda así: Código:
object Form1: TForm1
Left = 192
Top = 161
Width = 870
Height = 500
Caption = 'Form1'
...
object DoublePanel1: TDoublePanel
Left = 8
Top = 8
Width = 377
Height = 249
BevelOuter = bvLowered
Caption = 'DoublePanel1'
TabOrder = 0
TopPanelControlList = (
Edit1
Button1)
ClientPanelControlList = (
Memo1)
object Edit1: TEdit
Left = 8
Top = 8
Width = 121
Height = 21
TabOrder = 0
Text = 'Edit1'
end
object Button1: TButton
Left = 288
Top = 8
Width = 75
Height = 25
Caption = 'Button1'
TabOrder = 1
end
object Memo1: TMemo
Left = 8
Top = 8
Width = 185
Height = 89
Lines.Strings = (
'Memo1')
TabOrder = 0
end
end
end
Cada subpánel recorre su lista, busca la componente que tenga el nombre en turno en el formulario y le reasigna su padre. ---------------------------- Tod está ha salido de Ray Konopka. Busquen el artículo Compound Components del volúmen 8 para ver la componente original que él hizo. // Saludos |
|
|
|