PDA

Ver la Versión Completa : TCollection


Igna
24-06-2003, 11:26:40
Hola a todos.

Intentaré explicar mi duda de forma sencilla...Tengo un componente desarrollado por mi, descendiente de TStringGrid. Este componente tiene una propiedad de tipo TCollection. Lo que quiero hacer es que cuando se añada un nuevo item a la "coleción", se añada una nueva fila a mi componente (como hace el TDBGrid con las columns). Supongo que tendré que generar un evento cuando añada un nuevo item, y en el código del evento sumar una línea a mi componente, pero algo estoy haciento mal, por que me da errores.

Os pongo parte del código por si os aclara algo:

TNuevoUsuario = procedure (Sender: TObject) of object;


TUsuarios = class(TCollection)
private
FNuevoUsuario: TNuevoUSuario;
public
constructor Create(Owner : TPersistent);
destructor Destroy; override;
Function Add:TUsuariosItem;
function Insert(Index: Integer): TUsuariosItem;
property Items[Index: Integer]: TUsuariosItem
read GetItem
write SetItem;
property NuevoUsuario: TNuevoUsuario read FNuevoUsuario write FNuevoUsuario;

TOcupacion = class(TStringGrid)
private
FUsuarios: TUsuarios;
procedure NuevoUsuarioEvento(sender:TObject);

..............................

Function TUsuarios.Add:TUsuariosItem;
begin
result:=TUsuariosItem(Inherited Add);
if Assigned(NuevoUsuario) then
NuevoUsuario(Self);
end;

constructor TOcupacion.Create(AOwner: TComponent);
begin
Inherited;
FUsuarios := TUsuarios.Create(AOwner);
FUsuarios.NuevoUsuario := NuevoUsuarioEvento;
end;

procedure TOcupacion.NuevoUsuarioEvento(Sender: TObject);
begin
RowCount:=RowCount+1;
end;



Agradecería cualquier orientación sobre el tema.

Un saludo.

andres1569
24-06-2003, 12:03:13
Hola Igna, aquí van una serie de orientaciones:

Es recomendable que TUsuarios descienda de un TOwnedCollection en vez de un TCollection. El TOwnedCollection simplemente es un TCollection que implementa el método GetOwner (si mal no recuerdo), de esta forma Delphi puede mostrarlo desde el Object Inspector.

Otra cosa, el tipo de evento TNuevoUsuario es idéntico en su declaración al evento TNotifyEvent, así que lo puedes evitar.

El problema que sucede con el método Add (también con el Insert) de la clase TUsuarios es que devuelve un TUsuarioItem, no un TCollectionItem como en la clase TCollection, por eso es obligadamente un método no heredado. ¿Qué sucede? Que Delphi, cuando insertas un nuevo Item desde el IDE no llama a esa método Add sino al método Add de TCollection, y por lo tanto no se ejecuta el método Add que tú defines, consecuentemente tampoco se ejecuta el evento NuevoUsuario.

Otra cosa: cuando creas el objeto TUsuarios, debes pasarle como Owner tu componente (TOcupacion), es decir Self, no el Owner de TOcupacion (que normalmente será un Form o un Panel), y además hay que pasarle como parámetro la clase de los Items que va a manejar (TUsuarioItem); ésta es la forma que tienen los TCollection de saber qué Items deben crear cuando se llama a Add o Insert:

FUsuarios := TUsuarios.Create(Self, TUsuarioItem);

(te escribo de memoria, aquí no tengo el Delphi, pero creo que ese es el orden de los parámetros para un TOwnedCollection)

en vez de

FUsuarios := TUsuarios.Create(AOwner);

La solución que vengo empleando cuando uso colecciones y quiero hacer cosas de ese tipo que tú comentas, consiste en redefinir el método Create del TUsuarioItem, y ahí es donde se realiza el trabajo (ese método sabes seguro que se va a disparar). Sería una cosa como esta:

constructor TUsuarioItem.Create (ACollection: TCollection);
begin
inherited Create (ACollection);
if Assigned(ACollection) AND (ACollection is TUsuarios) then
TUsuarios(ACollection).NuevoUsuario(Self);
end;

Comprobamos que ACollection no es nil y que es del tipo TUsuarios (quizás demasiadas comprobaciones) y lanzamos el evento deseado.

Otra opción sería que la clase TUsuarios no tuviera definido ningún evento. Aún así podríamos lanzar el método NuevoUsuario de la clase TOcupacion, puesto que el TUsuarioItem tiene acceso al Owner del TUsuario que debe ser del tipo TOcupacion, algo así:

if Assigned(ACollection) AND Assigned(ACollection.Owner) AND
(ACollection.Owner is TOcupacion) then
TOcupacion(ACollection.Owner).NuevoUsuario(Self);

Como ves, son varias formas de hacerlo. Si te surge alguna duda ya nos dirás, creo que esto te debe funcionar.

Igna
24-06-2003, 12:24:14
Muchas gracias andres1569. Ahora me funciona perfecto.

Supongo que ahora me surgirán otros problemas (intentaré resolverlos antes de "molestaros" de nuevo). El componente que estoy creando es para ver la ocupación de los empleados leyendo los datos de los calendarios del outlook (creía que iba a ser más difícil, pero por ahora no va mal del todo la cosa).

Gracias de nuevo por tu rápida y extensa respuesta.

Un saludo.