Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   recorrer lista de controles hijos. (https://www.clubdelphi.com/foros/showthread.php?t=42151)

Byfed 05-04-2007 01:23:47

recorrer lista de controles hijos.
 
Hola a todos,

Tengo una duda. Habitualmente, cuando diseño una aplicación (suelen ser todas más o menos parecidas, de gestión, consultas a bases de datos y cosas así, no demasiado rebuscadas), suelo poner el formulario principal maximizado, y después ir construyendo las distintas secciones del programa en distintos frames.

Cuando se selecciona una opción del menú se esconden todos los frames y despues se hace visible el que corresponda. Esto me obliga a que en todos mis programas tengo que hacer una rutina de esconder_frames que es una pesadez:

frame1.hide;
frame2.hide;
.....
frame95.hide;

Cuando selecciono una opción del menu, hago:
escodertodos;
frameN.init;

y en el frameN he definido el procedimiento init, donde hago un self.show;
A parte, en ese procedimiento de inicio, que utilizo para cargar datos, si hacen falta, cargar opciones de combos, cosas así, suelo incluir también una rutina de limpiar_campos, donde tengo que recorrer todos los controles del frame haciendo:
Edit1.text := '';
Edit2.text := '';
...
Edit99.text := '';

Es muy repetitivo y una pesadez. Me preguntaba si no habrá alguna forma de otorgar un valor a una propiedad de un conjunto de controles del mismo tipo.En realidad me bastaría con saber como recorrer una lista de controles hijos.. así para hacer el esconder todos, podría ir recorriendo la lista desde el formularioprincipal y hacer

if tipocontrol(control)=Tframe then
control.hide

o en el init de cada frame, poder hacer

if tipocontrol(control)=Tedit then
control.text := '';

Espero haberme explicado bien. En realidad se puede resumir todo esto en que me gustaría saber si existe una forma de poder ir recorriendo todos los controles que están dentro de un formulario, un frame, o un groupbox.. sin tener que recurrir al nombre de cada control.

Gracias y un saludo.

vtdeleon 05-04-2007 01:38:51

Prueba con esto para los edits

Código Delphi [-]
Procedure Limpiar(Frame:Tframe);
var
  I:Integer;
begin
  For I:=Frame.ComponentCount-1 downto 0 then
    if Components[i] is TEdit then
      Tedit(Component[i]).Clear;
end;
Lo mismo lo puedes aplicar para los Frames.

roman 05-04-2007 01:41:48

Realmente no tienes que esconder todos los frames cada vez, sino únicamente el que estuviere visible al momento de activar otro. Una solución podrías ser la de llevar una variable

Código Delphi [-]
FrameActivo: TFrame;

que apunte al frame activo. Cuando muestres un frame pondrías algo como:

Código Delphi [-]
FrameActivo.Hide;
FrameAMostrar.Show;
FrameActivo := FrameAMostrar;

// Saludos

Byfed 05-04-2007 02:11:59

solución parcial.. una vuelta de tuerca más..
 
Encontré la solución haciendo lo siguiente:

Código:

procedure TFrameClientes.limpiar_detalle;
var
  i : integer;
begin
  for i:=0 to FormPrincipal.FrameClientes1.ComponentCount-1 do
      begin
        if (FormPrincipal.FrameClientes1.Components[i] is TEdit) then
            Tedit(FormPrincipal.FrameClientes1.Components[i]).text := '';
        if (FormPrincipal.FrameClientes1.Components[i] is TCheckBox) then
            TcheckBox(FormPrincipal.FrameClientes1.Components[i]).checked := false;
        if (FormPrincipal.FrameClientes1.Components[i] is TMemo) then
            TMemo(FormPrincipal.FrameClientes1.Components[i]).text := '';
        if (FormPrincipal.FrameClientes1.Components[i] is TComboBox) then
            begin
              TComboBox(FormPrincipal.FrameClientes1.Components[i]).text := '';
              TComboBox(FormPrincipal.FrameClientes1.Components[i]).itemindex := -1;
            end;
      end;
end;

Ahora quedaría otro reto.. y es hacer este procedimiento más general aún...
Que no lo tenga que escribir para cada frame.. sino que el frame fuera un parámetro y poder llamar al procedimiento como:

limpiar_detalle(FrameClientes1);

¿Alguien sabe cómo?

Salu2

vtdeleon 05-04-2007 02:20:49

Con el código que te di mas arriba, lo puedes hacer. El procedimiento capta un parametro de la clase TFrame.

vtdeleon 05-04-2007 02:22:30

Una pregunta,...Por qué no destruyes el Frame? antes de llamar al próximo.

Byfed 05-04-2007 02:23:30

lo encontré!!
 
Al final resultó ser una chorradilla...

Creé un fichero (suelo crearlo para meter en él todos los procedimientos "reutilizables") llamado unitFunciones que de momento solo contiene ésto:
Código:

unit UnitFunciones;

interface

uses Forms, StdCtrls;

procedure limpiar_detalle(frame: Tframe);

implementation

procedure limpiar_detalle(frame: Tframe);
var
  i : integer;
begin
  for i:=0 to frame.ComponentCount-1 do
      begin
        if (frame.Components[i] is TEdit) then
            Tedit(frame.Components[i]).text := '';
        if (frame.Components[i] is TCheckBox) then
            TcheckBox(frame.Components[i]).checked := false;
        if (frame.Components[i] is TMemo) then
            TMemo(frame.Components[i]).text := '';
        if (frame.Components[i] is TComboBox) then
            begin
              TComboBox(frame.Components[i]).text := '';
              TComboBox(frame.Components[i]).itemindex := -1;
            end;
      end;
end;


La llamada la hago desde el init de cada uno de los frames, haciendo:

Código:

limpiar_detalle(FormPrincipal.FrameClientes1);
y voilá...

Si me hubiera puesto a investigar esto antes.. cuántas horas de trabajo me había ahorrado... El ultimo programa que hice tenía unos 20 frames, y limpiaba los campos uno a uno!!!.. no se cuantas líneas de código.. pero una burrada.. bueno, de los errores se aprende.

Gracias a todos.

Byfed 05-04-2007 02:26:53

Cita:

Empezado por vtdeleon
Con el código que te di mas arriba, lo puedes hacer. El procedimiento capta un parametro de la clase TFrame.

Vaya... no me fijé en que usabas el frame como parámetro.... lo probé por mi cuenta y funcionó.. de todos modos, gracias.

Salu2

Byfed 05-04-2007 02:28:28

Cita:

Empezado por vtdeleon
Una pregunta,...Por qué no destruyes el Frame? antes de llamar al próximo.

Porque no siempre limpio todos los campos del frame cada vez que entro. Depende de si llamo a init con algún parámetro o no. En ocasiones, interesa que al volver al frame que dejaste, mantenga el estado en el que estaba.

Salu2

Byfed 05-04-2007 02:31:06

Joer.. Román.. como leches no he caido antes!!!.. si es que aún soy muy novato... en fin, muchas gracias de nuevo (utilizaré una variable de FrameActivo).

Nota: No os cuento la porrada de veces que he escrito un procedimiento para esconder todos los frames, porque me da vergüenza. :)

Saludos y gracias.

Lepe 05-04-2007 12:38:01

Ya puestos a trabajar de la forma de roman, se podría hacer algo más automático:

Código Delphi [-]

 TForm1 = class(TForm)

private
   FFrameActivo : TFrame;
  procedure SetFrameActivo(const Value:TFrame);
public
  FrameActivo :TFrame read FFrameActivo write SetFrameActivo;
...

procedure TFrom1.SetFrameActivo(const Value:TFrame);
begin
  if Assigned(FFrameActivo) and (FFrameActivo <> Value) then
  begin 
    FFrameActivo.Hide;
  end;
  FFrameActivo := VAlue;
  FFrameActivo.Show;
end;

Con este rollo, a partir de ahora solo tienes que hacer:
Código Delphi [-]
  FrameActivo := frame1;
y listo, se oculta el que se estaba viendo y se muestra el nuevo.

Saludos

Byfed 05-04-2007 16:41:33

Hola Lepe,

Gracias por tu respuesta, pero.. no es enrevesar demasiado las cosas?? No alcanzo a ver la ventaja de lo que propones.. aunque seguramente es porque no tengo conocimientos suficientes.

Aprovecho para ampliar mis horizontes y preguntarte por el código siguiente que has puesto en tu respuesta:

Código:

public
 FrameActivo :TFrame read FFrameActivo write SetFrameActivo;

Eso de "read" y "write" qué significa y para qué sirve?

Gracias de nuevo y un saludo.

Lepe 05-04-2007 18:43:25

Me equivoqué en esa línea, debería decir:
Código Delphi [-]
property FrameActivo :TFrame read FFrameActivo write SetFrameActivo;

Eso significa que cuando vamos a leer (read) la propiedad FrameActivo, en realidad se lee la variable FFrameActivo, típico en este caso:
Código Delphi [-]
var r:TFrame;
begin
  r := FrameActivo;
end

Y cuando se va a escribir (write) en esa variable, Ejemplo:
Código Delphi [-]
FrameActivo := Frame1;
Se ejecutará el procedimiento SetFrameActivo, con lo cual, podemos realizar otras operaciones. Además, como ese procedimiento lleva un parámetro, podemos saber si FFrameActivo ya tenía asignado el Frame1, el Frame2, o cualquier otro.

En el código delphi anterior, el parámetro "Value" será el valor que queremos asignar, es decir "Frame1".

Fíjate que antes de mi mensaje, tú tendrías que hacer lo dicho por roman, 3 líneas de código:
Código Delphi [-]
  FrameActivo.Hide;
  FrameAMostrar.Show;
  FrameActivo := FrameAMostrar;

A partir de ahora, es sólo una línea de código:
Código Delphi [-]
  FrameActivo := Frame1;

Mira cualquier unidad de delphi con clases, y verás que trabaja así internamente, es decir, no estoy inventando nada nuevo ;).

Saludos


La franja horaria es GMT +2. Ahora son las 06:22:10.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi