Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   OOP (https://www.clubdelphi.com/foros/forumdisplay.php?f=5)
-   -   Otro típico List Index Out Of Bounds (https://www.clubdelphi.com/foros/showthread.php?t=25967)

DarkByte 09-10-2005 21:15:41

Otro típico List Index Out Of Bounds
 
Wops!

Acudo a vosotros para pediros otra vez ayuda

Estoy intentando que el servidor me enumere las conexiones clientes... he creado un ListBox llamado "lbClients", una clase llamada Client, y un objeto TList llamado Clients donde guardo la lista de Client.

Código Delphi [-]

type
  TSimpleClient = class(TObject)
    DNS,
    Name        : String;
    ListLink    : Integer;
    Thread      : Pointer;
  end;

  TfrmLambda = class(TForm)
    IdTCPServer1: TIdTCPServer;
    lbClients: TListBox;
    //[...]
  private
    { Private declarations }
  public
    { Public declarations }
    Clients  : TList;
    procedure BroadcastMsg(Codigo,Mensaje:string);
    procedure UpdateClientList;
  end;

Bien. El TList se crea en el evento OnCreate del form... y se rellena de la siguiente manera:

Código Delphi [-]
procedure TfrmLambda.IdTCPServer1Connect(AContext: TIdContext);
var
  Client : TSimpleClient;
begin
  Client := TSimpleClient.Create;
  Client.DNS  := AContext.Connection.Socket.Binding.PeerIP;
  Client.Name := 'Registrandose';
  Client.ListLink := lbClients.Items.Count;
  Client.Thread := AContext;
  lbClients.Items.Add(Client.Name);
  AContext.Data := Client;
  Clients.Add(Client);
  AContext.Connection.IOHandler.Write('Nick: ');
end;

Cuando el cliente se desconecta, evidentemente, hay que quitarlo de en medio...

Código Delphi [-]
procedure TfrmLambda.IdTCPServer1Disconnect(AContext: TIdContext);
var
  Client : TSimpleClient;
begin
  Client := Pointer(AContext.Data);
  BroadCastMsg('004', '*** '+Client.Name+' se ha salido');
  Clients.Delete(Client.ListLink);
  lbClients.Items.Delete(lbClients.Items.IndexOf(Client.Name));
  Client.Free;
  AContext.Data := nil;
  UpdateClientList;
end;

Y nos falta el método por el cual actualizo la lista de clientes...
Código Delphi [-]
procedure TfrmLambda.UpdateClientList;
var
  Count : Integer;
begin
{ Loop through all the clients connected to the system and set their names }
  for Count := 0 to lbClients.Items.Count -1 do
    if Count < Clients.Count then
      lbClients.Items.Strings[Count] := TSimpleClient(Clients.Items[Count]).Name;
end;

Pues bien, gran parte de este código por no decir que prácticamente todo está cojido de un ejemplo de las indy que tenía por ahí y portado a Indy 10.

El programa me falla específicamente cuando un cliente se desconecta y hago clic en uno que esté por debajo (se ha conectado posteriormente). En el OnClic del ListBox tengo el siguiente código:

Código Delphi [-]
procedure TfrmLambda.lbClientsClick(Sender: TObject);
var
  Client : TSimpleClient;
begin
  if lbClients.ItemIndex = -1 then
    exit;
  Client := Clients.Items[lbClients.ItemIndex];
  lbNombre.Caption := Client.Name;
  lbIp.Caption  := Client.DNS;
end;

Muchísimas gracias a todos... y un abrazo

rounin 10-10-2005 10:06:29

Exprecion
Clients.Delete(Client.ListLink);
hace "ListLink" de todos los otros objetos "Client" invalidos
(si ListLink <> Clients.Count-1).

Usa
Clients.Remove(Client);

(o usa lbClients.Items.Objects)

DarkByte 10-10-2005 17:47:10

Aja, tengo claro que el fallo está en la parte Disconnect... pero supongo que no sé lo suficiente como para comprender tu post anterior. ¿Podría ser explicado de nuevo? Muchísimas gracias :)

vtdeleon 10-10-2005 18:15:55

Saludos

Tratando de entender un poco, creo que rounin trta de decirte que cambie esta parte Clients.Delete(Client.ListLink); por Clients.Remove(Client);

Haz la prueba, ya que nuestro amigo rouni tiene un poco de problema con el español.

No comprendo bien el codigo(nunca he tratabajo con indy)

DarkByte 10-10-2005 20:52:42

Funciona de maravillas!!!

MUUUUAKS!!! :P

rounin 10-10-2005 21:06:41

Saludos,

Perdoname por mi mal español.

Trato explicar mas completo.
Ahora usas dos listas para guardar TClient
(lbClients.Items y Clients)
y tratas sincronizarlas en varios lugares.
En principle eso es possible, pero mejor
o usar una lista,
o sincronizar en solo una lugar (cada vez borrar una
y rellenar).
En cualquier caso no es buena idea guardar
indices en lista (como ListLink), porque las operaciones
Add, Remove, Insert cambian orden de objetos en lista.

El mas simplemente manera en tu case es usar
solo una lista (lbClientes.Items.Objects)
y no sincronizar nada:

Código Delphi [-]
 
{...}
//ListLink : Integer; // no necesita
{...}
//Clients : TList; // no necesita
{...}
 
procedure TfrmLambda.IdTCPServer1Connect(AContext: TIdContext);
var
  Client : TSimpleClient;
begin
  Client := TSimpleClient.Create;
  Client.DNS := AContext.Connection.Socket.Binding.PeerIP;
  Client.Name := 'Registrandose';
 
  //Client.ListLink := lbClients.Items.Count;
 
  Client.Thread := AContext;
 
  //lbClients.Items.Add(Client.Name);
  lbClients.Items.AddObject(Client.Name, Client);
 
  AContext.Data := Client;
 
  //Clients.Add(Client);
 
  AContext.Connection.IOHandler.Write('Nick: ');
end;
 
procedure TfrmLambda.IdTCPServer1Disconnect(AContext: TIdContext);
var
  Client : TSimpleClient;
begin
  Client := Pointer(AContext.Data);
  BroadCastMsg('004', '*** '+Client.Name+' se ha salido');
 
  //Clients.Delete(Client.ListLink);
 
  //lbClients.Items.Delete(lbClients.Items.IndexOf(Client.Name));
 
  lbClients.Items.Delete(lbClients.Items.IndexOf(Client.Name));
  Client.Free;
  AContext.Data := nil;
  UpdateClientList;
end;
 
//procedure TfrmLambda.UpdateClientList; // no necesita
 
procedure TfrmLambda.lbClientsClick(Sender: TObject);
var
  Client : TSimpleClient;
begin
  if lbClients.ItemIndex = -1 then
    exit;
 
  //Client := Clients.Items[lbClients.ItemIndex];
  Client := lbClients.Items.Objects[lbClients.ItemIndex];
 
  lbNombre.Caption := Client.Name;
  lbIp.Caption := Client.DNS;
end;

DarkByte 10-10-2005 21:55:28

Muchísimas gracias por la explicacion.

Veo que ha puesto todo el foco sobre el TListBox en vez de el TList... podría funcionar. Muchísimas gracias, voy a probarlo

De cualquier forma, si puede decirme su lenguaje nativo o uno que domine mejor que el castellano, podemos intentar cambiar a ese para ahorrar molestias :)

vtdeleon 10-10-2005 22:42:25

Saludos
Cita:

Empezado por DarkByte
De cualquier forma, si puede decirme su lenguaje nativo o uno que domine mejor que el castellano, podemos intentar cambiar a ese para ahorrar molestias :)

Lamentablemente, aquí la guía de estilo dice esto....

DarkByte 10-10-2005 22:45:53

Claro, hace tiempo que estoy en el foro... :)

Por eso tenía pensado poner mis mensajes en ambos lenguajes, así no falto a ella y obtengo una respuesta más precisa.

Gracias por el toque, vtdeleon ;)

roman 11-10-2005 02:08:53

Vamos a hacer una pequeña aclaración en cuanto al lenguaje a utilizar en los foros.

Primeramente, es cierto que la guía de estilo implica que el lenguaje oficial de los foros es el español, y no creo que esto vaya a cambiar.

Sin embargo, no será ésta la primera vez que se haga una excepción. Ya en ocasiones anteriores se han entablado hilos en portugués.

Al forista rounin me gustaría expresarle dos cosas:

1. Siéntete bienvenido en estos foros, agradecemos toda la colaboración que has prestado desde tu ingreso.

2. De ser posible, trata de escribir tus mensajes en español. Pero si te enfrentas con situaciones que te sea difícil expresar, siéntete en libertad de hacerlo en inglés; varios moderadores estamos en la disposición, de ser necesario, de llevar a cabo una traducción de aquello que pueda no entenderse.

// Saludos


La franja horaria es GMT +2. Ahora son las 07:24:51.

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