Ir al contenido


Foto

Como seleccionar multiples controles (TImages) y moverlos


  • Por favor identifícate para responder
10 respuestas en este tema

#1 JoAnCa

JoAnCa

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 775 mensajes
  • LocationPinar del Río, Cuba

Escrito 22 febrero 2017 - 02:37

Hola a todos
Pues estoy diseñando un soft de monitoreo de red, que incluye un mapa de red (usando TImages), que ya esta funcionando bien, pero quisiera mejorarlo un poco.

Necesito ahora que se puedan seleccionar multiples TImages (nodos), ya sea presionando Ctrl o Shift, o arrastrando con el mouse un recuadro que seleccione a los que contenga en su interior, y poder mover todos los nodos seleccionados

Con este codigo, logor mover cada nodo con su etiqueta asociada, pero solo uno a la vez


delphi
  1. //----- Para Seleccionar y Mover el Nodo -----
  2. procedure TfrmPrincipal.ControlMouseDown( Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer );
  3. begin
  4. CompCorX:=X;
  5. CompCorY:=Y;
  6. CompMoviendo:=True;
  7. TMovible(Sender).MouseCapture:=True;
  8.  
  9. //--- Resaltar Nodo Seleccionado ---
  10. with shpSelect do
  11. begin
  12. Parent:=(Sender as TsImage).Parent;
  13. Visible:=True;
  14. Top:=TsImage(Sender).Top-1;
  15. Left:=TsImage(Sender).Left-1;
  16. end;
  17. end;
  18.  
  19. procedure TfrmPrincipal.ControlMouseMove( Sender: TObject; Shift: TShiftState; X, Y: Integer );
  20. begin
  21. if CompMoviendo then
  22. begin
  23. TImage(Sender).Left:=TImage(Sender).Left - (MouseDownSpot.x - x) - 24;
  24. TImage(Sender).Top:=TImage(Sender).Top - (MouseDownSpot.y - y) - 24;
  25.  
  26. //--- Mover la etiqueta asociada ---
  27. lblDisp:=TLabel(FindComponent(TImage(Sender).Hint));
  28. lblDisp.Left:=TImage(Sender).Left+25 - Round(lblDisp.Width/2);
  29. lblDisp.Top:=TImage(Sender).Top + TImage(Sender).Height + 2;
  30.  
  31. //--- Resaltar Nodo Seleccionado ---
  32. with shpSelect do
  33. begin
  34. SendToBack;
  35. Visible:=True;
  36. Top:=TsImage(Sender).Top-1;
  37. Left:=TsImage(Sender).Left-1;
  38. end;
  39. end;
  40. end;
  41.  
  42. procedure TfrmPrincipal.ControlMouseUp( Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer );
  43. begin
  44. if CompMoviendo then
  45. begin
  46. CompMoviendo:=False;
  47. TMovible(Sender).MouseCapture:=False;
  48. end;
  49.  
  50. //----- Para guardar las nuevas coordenadas en la BD -----
  51. if (Sender is TImage) then imgSelect:=TImage(Sender);
  52. NombDisp:=Copy(imgSelect.Name, 4, Length(imgSelect.Name));
  53. with DataMod do
  54. begin
  55. if (Sender as TsImage).Parent = sbMapaRed then
  56. begin
  57. fdtRedes.Locate('IdRed', NombDisp, []);
  58. fdtRedResum.Locate('IdRed', NombDisp, []);
  59. fdtRedes.Edit;
  60. fdtRedesPosX.Value:=imgSelect.Left;
  61. fdtRedesPosY.Value:=imgSelect.Top;
  62. fdtRedes.Post;
  63. end;
  64. if (Sender as TsImage).Parent = sbMapaLAN then
  65. begin
  66. fdtDisposit.Locate('IdDisp', NombDisp, []);
  67. fdtDispInf.Locate('IdDisp', NombDisp, []);
  68. fdtDisposit.Edit;
  69. fdtDispositPosX.Value:=imgSelect.Left;
  70. fdtDispositPosY.Value:=imgSelect.Top;
  71. fdtDisposit.Post;
  72. end;
  73. end;
  74. end;

Como modificaria el código para lograr lo que quiero ?
O que tengo que agregar ?


Editado por JoAnCa, 22 febrero 2017 - 02:40 .

  • 0

#2 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 22 febrero 2017 - 03:49

Me tendría que dar un tiempo para pensarlo un rato, pero el 1er cambio que hay que hacer es disponer de un array o una lista de TImages en la que pongan los TImages seleccionados.

De este modo cuando se mantenga presionada la tecla Shift o Ctrl (tu verás) detectar que se está en modo "Selección múltiple" y ahora cada vez que se haga un click en un TImage lo agregamos a la lista.

Con la lista definitiva, lo que resta es ir recorriendola para ir desplazando los objetos. Por ejemplo, si el mouse se mueve (x+5, y-8) a todos los TImages en la lista lo movemos en forma proporcional a esto. Es decir, que si por ejemplo la escala del mapa es 1:1, cada pixel en pantalla implica una posición del mapa y por tanto a todos los objetos de la lista lo movemos (+5, -8)

 

El algoritmo finaliza cuando se suelta el mouse, que es cuando la lista se libera (ojo: no liberar los objetos de la lista, simplemente la "limpiamos") para "deseleccionar" los TImages. Es un juego de eventos como lo vienes haciendo; lo que lo hace diferente es que ahora en lugar de tener uno tienes una lista. Nota que esta lista sirve inclusive para un único elemento (Count = 1) asi que al iniciar el programa (o el form/módulo, tu verás) puedes crear por ejemplo un TObjectList que inicialmente no tendrá items, y a medida que se trabaja, se agregan y se quitan.

 

Espero que se entienda.

 

Saludos,


  • 0

#3 JoAnCa

JoAnCa

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 775 mensajes
  • LocationPinar del Río, Cuba

Escrito 22 febrero 2017 - 03:56

Me tendría que dar un tiempo para pensarlo un rato, pero el 1er cambio que hay que hacer es disponer de un array o una lista de TImages en la que pongan los TImages seleccionados.

De este modo cuando se mantenga presionada la tecla Shift o Ctrl (tu verás) detectar que se está en modo "Selección múltiple" y ahora cada vez que se haga un click en un TImage lo agregamos a la lista.

Con la lista definitiva, lo que resta es ir recorriendola para ir desplazando los objetos. Por ejemplo, si el mouse se mueve (x+5, y-8) a todos los TImages en la lista lo movemos en forma proporcional a esto. Es decir, que si por ejemplo la escala del mapa es 1:1, cada pixel en pantalla implica una posición del mapa y por tanto a todos los objetos de la lista lo movemos (+5, -8)

 

El algoritmo finaliza cuando se suelta el mouse, que es cuando la lista se libera (ojo: no liberar los objetos de la lista, simplemente la "limpiamos") para "deseleccionar" los TImages. Es un juego de eventos como lo vienes haciendo; lo que lo hace diferente es que ahora en lugar de tener uno tienes una lista. Nota que esta lista sirve inclusive para un único elemento (Count = 1) asi que al iniciar el programa (o el form/módulo, tu verás) puedes crear por ejemplo un TObjectList que inicialmente no tendrá items, y a medida que se trabaja, se agregan y se quitan.

 

Espero que se entienda.

 

Saludos,

 

Pues te entendi bien la explicacion, lo que aun no se me ocurre como implementarlo :(

De todos modos, si encuentra la solucion primero, la publicas, igual hare yo si logro hacerlo


  • 0

#4 JoAnCa

JoAnCa

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 775 mensajes
  • LocationPinar del Río, Cuba

Escrito 23 febrero 2017 - 08:47

Pues ya modifique el codigo para usar una lista TObjectList, y veo q es mas facil para todo

Ya cambie lo de agregar y eliminar nodos, pero todavia no he podido con lo de la seleccion multiple  :undecided: 


  • 0

#5 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 831 mensajes
  • LocationArgentina

Escrito 23 febrero 2017 - 06:07

Estoy desde el móvil ahora, pero una TObjectList no se hace cargo del manejo de memoria de lo que le metas adentro? Creo que había un método Extract que lo que hacía era quitar el elemento de la lista y retornarlo pero no liberar la memoria

Que versión de Delphi estás usando?
  • 0

#6 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 23 febrero 2017 - 08:19

Estoy desde el móvil ahora, pero una TObjectList no se hace cargo del manejo de memoria de lo que le metas adentro? Creo que había un método Extract que lo que hacía era quitar el elemento de la lista y retornarlo pero no liberar la memoria

Que versión de Delphi estás usando?

 

Depende del valor que se pase al parámetro AOwnsObject. Si es true el mismo se encarga de la liberación de los objetos que se agreguen al momento de un Free. Cuando es false la responsabilidad es nuestra. Y si, tiene el método Extract(), y también el ExtractItem().

 

En los nuevos Delphi está definido como genérico por lo que podemos incluso hacer un TObjectList<TImage>.

 

Saludos,


  • 0

#7 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 831 mensajes
  • LocationArgentina

Escrito 23 febrero 2017 - 10:30

Cuidado. No solo en el destructor. Si indicamos OwnsObjects a True, estamos diciendo a la lista que es la responsable de los tiempos de vida y el manejo de la memoria. Aquí lo dice la doc http://docwiki.embar...nrs.TObjectList

Una eliminación de un objeto de la lista provoca que sea liberado de memoria invocando al destructor, esto claro si OwnsObjects es True

Tener en cuenta que es el comportamiento por defecto, ya que el constructor define como valor por defecto para el parámetro AOwnsObjects como True
  • 0

#8 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 23 febrero 2017 - 10:40

Así es. La palabra Owner lo deja en claro ;)
Pensé que se sobreentendía de mis palabras. Haces bien en comentarlo de forma explícita.

Saludos
  • 0

#9 JoAnCa

JoAnCa

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 775 mensajes
  • LocationPinar del Río, Cuba

Escrito 24 febrero 2017 - 07:43

Bueno ahora si me perdi con lo de la lista de objetos, paerece mas complicado de lo que pense, habia usado listas, pero strinlist y parecidas, nunca de objetos (TObjectList)  :|

 

Por cierto, lo de insertar y eliminar me salio bien, pero lo de sacar el objeto (TImage) para obtener sus propiedades (posición, nombre, hint) no supe hacerlo, y ahora con lo que me explican veo que se me complican un poco las cosas

 

Y lo de la selección multiple, por mas que lo intento no me sale :s

 

 

Que versión de Delphi estás usando?

 

Estoy usando Delphi XE7


Editado por JoAnCa, 24 febrero 2017 - 07:45 .

  • 0

#10 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 831 mensajes
  • LocationArgentina

Escrito 24 febrero 2017 - 08:40

En tu caso lo mejor sería usar TList. Y ya que tenés genéricos, mejor una TList<TImage> de la unidad System.Generics.Collections, como comento Delphius.

No puedo ponerme a probar nada (sin luz hace 15 hrs, un desastre)

Quizá me confundí, pero había entendido que solo en el destructor de TObjectList se liberaban los objetos de la lista. Puesto que nunca use propiamente una TObjectList me puse a leer la wiki
  • 0

#11 JoAnCa

JoAnCa

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 775 mensajes
  • LocationPinar del Río, Cuba

Escrito 24 febrero 2017 - 01:04

Pues parece que ya encontre la solución a mi problema, todo esto y mas  se resuelve con el componente cyResizer de la colección Cindy Components

 

Lo que ahora me falta como guardar la nueva posición de los nodos, para que se carguen en ella la proxima vez que se abra el mapa de red


Editado por JoAnCa, 24 febrero 2017 - 01:08 .

  • 0




IP.Board spam blocked by CleanTalk.