delphi reference runtime components

Delphi: referencia de componentes creados en tiempo de ejecución



reference runtime (4)

Estoy usando Delphi 5 y estoy creando varios paneles en tiempo de ejecución, luego creo botones en los paneles, obviamente nuevamente en el tiempo de ejecución. Necesito hacerlo de esta manera porque es posible que necesite crear dinámicamente más combinaciones de panel / botón en el futuro.

Puedo hacer todo esto, pero no sé cómo hacer referencia a los paneles que he creado, porque no puedo encontrar la manera de acceder al nombre del componente de los paneles. Buscando en Internet He descubierto que puedo usar FindComponent para encontrar los componentes del panel por nombre, pero sigo sin saber cómo usar ese nombre, porque no puedo usar una variable de cadena para referirme a él, por ejemplo, StringVar. : = Panel.Name. Obtengo una discrepancia de tipo, TComponentName versus String.

Creé los botones para cada panel cuando creé los paneles. Simplificado, se ve así:

With TypeQuery do begin // Create Panels First; While (not eof) do begin // create the actual panel panelno := FieldByName(''Product_type_id'').AsInteger; pnl := Tpanel.Create(Self); pnl.name := FieldByName(''PanelName'').AsString; pnl.color := clInactiveCaption; pnl.parent := MainForm; pnl.width := 365; pnl.Height := 551; pnl.left := 434 pnl.top := 122; pnl.caption := ''''; With ButtonQuery do begin Close; Parameters.parambyname(''PanelID'').Value := PanelNo; Open; First; While (not eof) and (FieldByName(''Product_type_id'').AsInteger = PanelNo) do begin //put the buttons on it. btnName := FieldByName(''ButtonName'').AsString; BtnText := FieldByName(''ButtonText'').AsString; BtnGroup := FieldByName(''Product_Group_ID'').AsString; GrpColour := FieldByName(''ButtonColour'').AsString; btn := TColorButton.Create(Self); btn.Parent := pnl; btn.Name := BtnName; Btn.backcolor := HexToTColor(GrpColour); btn.Font.Name := ''Arial Narrow''; btn.Font.Style := [fsBold]; btn.Font.Size := 10; . . . end; . . . end; end;

He leído en varios foros (incluido este) que no hay forma de hacer referencia directamente a los paneles por nombre. Intenté usar una matriz de componentes, pero me parece que tengo el mismo problema: necesito referirme al componente por su nombre de componente asignado.

De acuerdo, no soy un programador de armas: he usado Delphi durante años para crear programas simples, pero este es mucho más complejo. Nunca he trabajado con la creación de componentes en tiempo de ejecución.

¿Puedo usar FindComponent para hacer que los paneles sean visibles o invisibles? Si es así, dado lo que le he mostrado arriba, ¿puede darme el enfoque que debería tomar en pasos de bebé?

Gracias por adelantado ...


Está combinando el nombre del componente con el nombre de la variable . Delphi IDE se esfuerza por mantener esos dos iguales para los componentes creados por IDE, pero no necesariamente son iguales. No tiene nombres de variables porque está creando los componentes dinámicamente y no sabe cuántas variables necesitará. Sin embargo, aún tiene control sobre los nombres de los componentes: simplemente asigne la propiedad Name del componente y luego puede usarlo de la misma forma que usa los nombres de otros componentes, llamando a FindComponent . Solo asegúrese de que los nombres sean únicos para cada instancia del panel.

Recuerde también que la forma de manejar las variables, cuando no sabe en tiempo de compilación, cuántas necesitará, es usar matrices o listas . Puede usar arrays antiguos simples, o puede usar una estructura de datos más sofisticada como TComponentList o TDictionary .

Finalmente, para que sea más fácil referirse a los controles en los paneles que está creando, puede prescindir de los paneles y usar marcos en su lugar. Puede diseñar visualmente un TFrame en el IDE y dar nombres a los botones, y en el tiempo de ejecución, puede instanciar la clase de marco, y automáticamente creará todos los botones, al igual que al crear una instancia de un formulario o módulo de datos. Solo necesita dar un nombre al nuevo objeto de marco, pero ese objeto ya tendrá campos con nombre que hacen referencia a los botones.


No debería haber necesidad de crear una lista secundaria de elementos que haya creado para mostrar en una instancia de tForm.

AFAIK, cada vez que creas un nuevo panel que usa un Formulario u otro Contenedor en lugar de uno mismo

pnl := Tpanel.Create(Self);

no es necesario que se ocupe de destruir la nueva pnl, ya que es manejada por el componente "auto" que lo contiene.

Esto significa que debe haber cualquier construcción que contenga los componentes secundarios del componente principal.

Espero que encuentre una lista ComponentCount o Components o un método FindComponent en el objeto principal. Asumiendo que el objeto "Self" referido es una Tform.

for i := 0 to tForm(self).ComponentCount -1 do if tForm(self).Components[i] is tPanel then tPanel(tForm(self).Components[i]).Caption := intToStr(i) ;

cambiará todos los subtítulos de tPanels en su aplicación. Para distinguir entre paneles creados por código y diseñador, puede usar la propiedad TAG de cada tPanel creado y usarla en el ejemplo anterior.


No estoy seguro de lo que quiere decir con: " No puedo usar una variable de cadena para referirme a ella, por ejemplo, StringVar: = Panel.Name " .

Prueba esto:

procedure TForm1.FormCreate(Sender: TObject); var p: TPanel; begin p := TPanel.Create(Self); // create a TPanel at run-time p.Name := ''MyPanel''; // set a unique name p.Parent := Self; end; procedure TForm1.Button1Click(Sender: TObject); var p: TPanel; StringVar: string; begin p := FindComponent(''MyPanel'') as TPanel; if Assigned(p) then // p has reference to MyPanel begin // use that reference p.Caption := ''Foo''; StringVar := p.Name; ShowMessage(StringVar); end; end;

¿O me perdí algo?


Puede agregar los componentes que necesita referencias a un TList | contenedor ... y luego, use su lista | contenedor para acceder a ellos

var slPanels: TStringList; ... With TypeQuery do begin // Create Panels First; While (not eof) do begin // create the actual panel panelno := FieldByName(''Product_type_id'').AsInteger; pnl := Tpanel.Create(Self); pnl.name := FieldByName(''PanelName'').AsString; slPanels.AddObject(FieldByName(''PanelName'').AsString, pnl);

Cuándo lo necesitas:

TPanel(slPanels.Objects[slPanels.IndexOf(FieldByName(''PanelName'').AsString)]) ...

No me gusta el código anterior (hay mejor contenedor ... pero esto debería hacer el trabajo: o))