delphi - ¿Cómo crear dinámicamente controles alineados con la parte superior pero después de otros controles alineados?
controls alignment (3)
En este caso particular, estoy usando la biblioteca PowerPDF para construir dinámicamente un documento PDF, pero lo mismo aplica para el concepto general de alinear dinámicamente controles secuencialmente dentro de un control padre. En esta biblioteca, TPRPage
es el control base que contiene todos los controles de elementos, en este caso, instancias secuenciales de TPRLayoutPanel
.
Lo que hago cuando dinámicamente agrego controles:
- Crear un control (
TPRLayoutPanel
) - Establecer el padre del control (
TPRPage
) - Alinee el control hacia arriba (
PRLayoutPanel.Align:= alTop;
)
El problema es que se fuerza desde el principio (arriba) en lugar del final (abajo) de la página.
Intenté configurar su orden PRLayoutPanel.SendToBack;
o PRLayoutPanel.BringToFront
pero sin suerte.
¿Cómo puedo crear dinámicamente y alinear controles múltiples dentro de un control padre secuencialmente? Mi única solución actual es agregar los controles en orden inverso (de principio a fin), lo cual es ridículamente innecesario.
Aquí está mi función universal que crea cada instancia nueva de un control alineado en este elemento principal:
function TfrmReport.InsertPanel: TPRLayoutPanel;
begin
Result:= TPRLayoutPanel.Create(PRPage);
Result.Parent:= PRPage;
Result.Align:= alTop;
Result.Height:= 40; //Default, may change later
end;
Necesita configurar la propiedad Top
para que sea la parte inferior del panel anterior. Por ejemplo, así:
PanelTop := 0;
for i := 0 to 5 do
begin
Panel[i] := TPanel.Create(Self);
Panel[i].Parent := Self;
Panel[i].Height := PanelHeight;
Panel[i].Align := alTop;
Panel[i].Top := PanelTop;
inc(PanelTop, PanelHeight);
end;
Para adaptarlo a su código, debe realizar un seguimiento de la ubicación del panel agregado más recientemente. Quizás podría agregar un parámetro var
a su función InsertPanel
:
function TfrmReport.InsertPanel(var PanelTop: Integer): TPRLayoutPanel;
begin
Result:= TPRLayoutPanel.Create(PRPage);
Result.Parent:= PRPage;
Result.Top:= PanelTop;
Result.Height:= 40;
Result.Align:= alTop;
inc(PanelTop, Result.Height);
end;
¡Confío en que entiendas la idea!
Puede utilizar el tipo de alineación AlCustom y controlar todas las posiciones de sus paneles mediante el método CustomAlignPosition (deberá anularlo en control principal). Esto le dará más flexibilidad y control.
Una vez más, DisableAlign
y EnableAlign
al rescate:
procedure TForm1.FormCreate(Sender: TObject);
var
I: Integer;
P: TPanel;
begin
DisableAlign;
try
for I := 0 to 4 do
begin
P := TPanel.Create(Self);
P.Caption := IntToStr(I);
P.Align := alTop;
P.Parent := Self;
end;
finally
EnableAlign;
end;
end;
Explicación:
Cuando la alineación está habilitada , cada adición de un control a un contenedor (el formulario en sí en este caso específico) volverá a evaluar todas las configuraciones de alineación (y anclaje) de todos los otros controles dentro de ese contenedor. En caso de que el control no tenga un conjunto de propiedades Top
específico, Top
será 0
. Cuando ya hay otro control alineado a la parte superior, hay dos controles con Top = 0
, y el que está a punto de insertarse gana. Yo (actualmente) no tengo una explicación en profundidad para eso, pero simplemente lo es, y el orden de posición realmente se revierte del orden de creación.
Ahora, cuando la alineación del contenedor está desactivada , los controles agregados consecutivos simplemente se insertan con todas sus propiedades de posicionamiento inalteradas. Cuando la alineación se habilita de nuevo, todos los controles se vuelven a evaluar de la misma manera, con la diferencia de que esto tiene lugar en un solo bucle en el orden del índice en la matriz Controls
; es decir, el orden en que fueron creados.