PDA

Ver la Versión Completa : Clase TghObjList


Al González
17-05-2013, 03:53:30
Mantiene una lista de objetos a los que permite aplicar varios tipos de tareas de forma fácil y segura.

Unidad

GHFObjList

Declaración
{ Object List class }
TghObjList = Class (TObjectList)
...
Descripción

La clase TghObjList extiende las características de su clase padre, la nativa TObjectList, añadiendo diversas funcionalidades:


Actualización automática de la lista cuando alguno de los objetos, siendo un componente, resulta destruido (como lo hace TComponentList).
Agregación de objetos según su clase desde otros contenedores (propiedad Components de objetos TComponent, listas TStrings, otras listas TObjectList).
Llamadas múltiples, con una sola instrucción, a un método específico de todos los objetos de la lista, o solamente los que sean de una clase en particular.
Clonación parcial o total de la lista, creando otra instancia TghObjList.
Enumeración segura de todos los objetos de la lista, o solamente los que sean de una clase en particular.

Se entiende por enumeración al mecanismo por el cual una serie de elementos son utilizados para llamar varias veces a una rutina (función, procedimiento o método), siendo esa rutina proporcionada por el programador y ejecutada una vez por cada elemento, sin que el programador tenga que escribir el código que realiza las llamadas. Este tipo de rutinas se conocen como de retrollamada (en inglés, call back).

En TghObjList todas las enumeraciones son seguras, en el sentido de que a la lista se le pueden agregar o eliminar objetos durante el proceso de enumeración, sin que por ello se incurra en violaciones de acceso o se pase por alto ninguno de los objetos que se mandó enumerar (mientras éstos sigan en la lista).

Ejemplo comparativo

Suponga que tenemos un formulario con varios componentes TEdit y un botón, y hemos implementado el evento OnChange del segundo TEdit (Edit2) y el evento OnClick del botón:
TForm1 = class(TForm)
Edit1: TEdit;
Edit2: TEdit;
Edit3: TEdit;
...
Button1: TButton;
procedure Edit2Change(Sender: TObject);
procedure Button1Click(Sender: TObject);
end;

...

implementation

{$R *.dfm}

procedure TForm1.Edit2Change(Sender: TObject);
begin
// If Edit2 is cleared, we destroy Edit1 and show a message to user.
If Edit2.Text = '' Then
Begin
Edit1.Free;
ShowMessage ('You must enter a value for Edit2.');
Edit2.SetFocus;
End;
end;

procedure TForm1.Button1Click(Sender: TObject);
Var
I :Integer;
begin
// We clear all TEdit components
For I := ComponentCount - 1 DownTo 0 Do
If Components [I] Is TEdit Then
TEdit (Components [I]).Clear;
end;
El código anterior utiliza el evento OnChange del cuadro de texto Edit2 para validar si éste ha quedado vacío, en cuyo caso destruye el cuadro de texto Edit1, muestra un mensaje al usuario y se asegura de que el foco quede en Edit2. El segundo manejador de eventos se ejecuta cuando el botón es presionado. Se trata de un típico ciclo "ComponentCount - 1 DownTo 0" sobre los componentes del formulario, cuyo propósito en este ejemplo es llamar al método Clear de cada objeto TEdit, es decir, el código de Button1Click es para poner en blanco todos los edits.

El código funciona, pero surge un problema: Cuando el ciclo llama al método Clear de Edit2, disparándose con ello el manejador de eventos Edit2Change con la esperada destrucción del objeto Edit1, los componentes del formulario se reacomodan en su lista interna representada por la propiedad Components, de tal manera que Edit2 se mueve de la posición n a la posición n - 1. Esto causa que la siguiente pasada del ciclo For se ejecute nuevamente con el mismo componente (Edit2), derivando en una segunda llamada al método Clear de ese objeto, y por consecuencia una segunda e innecesaria ejecución del manejador Edit2Change (dos veces se muestra en pantalla el mensaje "You must enter a value for Edit2").

El recorrido de objetos mediante simples ciclos ascendentes (0 To Count - 1) o descendentes (Count - 1 DownTo 0) es útil y seguro en gran cantidad de casos, pero no así cuando alguna de las pasadas del ciclo tiene el potencial del alterar el contenido de la lista recorrida. TghObjList ofrece un mecanismo de enumeración que inicia con una "toma instantánea" de los objetos a recorrer (emplea para ello una lista interna auxiliar), de tal suerte que el proceso es seguro contra agregaciones, eliminaciones o reacomodos ocurridos durante el mismo.

El siguiente sería el código para el manejador de eventos Button1Click, usando enumeración segura con TghObjList. Sólo una vez se llama al método Clear de Edit2, y por ende sólo una vez se dispara Edit2Change.
implementation

{$R *.dfm}

Uses
GHFObjList;

...

procedure TForm1.Button1Click(Sender: TObject);
begin
// We create an instance of TghObjList
With TghObjList.Create (False) Do
Try
// We add the TEdit components of Form1 to the object list
AddComponents (Self, TEdit);

// We call to the Clear method of all objects in the list
Call (@TEdit.Clear);
Finally
Free; // We destroy the object list instance
End;
end;

ElKurgan
17-05-2013, 19:49:56
Muchas gracias por el aporte, maestro

v:-)vv:-)vv:-)v

Casimiro Notevi
17-05-2013, 20:02:11
Interesante :)

fjcg02
17-05-2013, 23:08:23
Estos son los pequeños ejemplos que le faltan a la biblioteca para que despeguen definitivamente.

Y algún pequeño ejemplo práctico de uso.

Gracias Al