Ir al contenido


Foto

TTimer y TPanels creados en tiempo de ejecución


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

#1 Fleon

Fleon

    Advanced Member

  • Miembros
  • PipPipPip
  • 172 mensajes
  • LocationRepública Dominicana

Escrito 21 enero 2016 - 03:40

Hola a todos, tengo un panel que crea x cantidad de panels dentro de ellas (Asignandoles un tamaño de ancho de acuerdo al ancho del panel contenedor), hasta aquí todo bien, salvo dos detalles que no sé cómo atacar, dejo el código y expongo mis dudas más abajo:


delphi
  1.  
  2. procedure TForm1.FormCreate(Sender: TObject);
  3.  
  4. var
  5.  
  6.   b: Integer;
  7.  
  8.   Barra: TPanel;
  9.  
  10. begin
  11.  
  12.   for b := 0 to 39 do
  13.  
  14.   begin
  15.  
  16.     Barra := TPanel.Create(Self);
  17.  
  18.     Barra.Parent := pnBarras;
  19.  
  20.     Barra.Name := 'Bar' + IntToStr((b + 1)); //Bar1, Bar2, Bar3, etc..
  21.  
  22.     Barra.Caption := '';
  23.  
  24.     Barra.ParentBackground := False;
  25.  
  26.  
  27.  
  28.     case b of
  29.  
  30.       0..22:  Barra.Color := clLime;
  31.  
  32.       23..34: Barra.Color := clYellow;
  33.  
  34.       35..40: Barra.Color := clRed;
  35.  
  36.     end;
  37.  
  38.  
  39.  
  40.     Barra.Align := alLeft;
  41.  
  42.     Barra.Width := round(pnBarras.Width div 40);
  43.  
  44.     //Barra.Free;
  45.  
  46.   end;
  47.  
  48. end;

1. En este caso creo 40 panels dentro de otro panel pero no queda ajustado, deja un espacio al final equivalente a 3 o cuatro panels, ¿ cómo llenar los 40 panels y que ocupe el panel contenedor por completo?.

 

2. Haciendo uso de TTimer quiero lograr que cada segundo que pase cada panel creado en ejecución cambie a color negro por ejemplo, pero como los paneles no están creados sino después no sé cómo ordenar al componente 'tal' cambie de color.

 

lo que estoy haciendo es mi propio Barra de progreso, ya que por defecto trae delphi no satisface mis necesidades.

 

Fleon xDD

 

 

Archivos adjuntos


  • 0

#2 Wilson

Wilson

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2.137 mensajes

Escrito 21 enero 2016 - 04:54

Para resolver lo del ancho de la barra intenta con esto:


delphi
  1. procedure TForm1.FormCreate(Sender: TObject);
  2.  
  3. var
  4.  
  5. b: Integer;
  6.  
  7. Barra: TPanel;
  8.  
  9. begin
  10. pnBarras.Width := 0;
  11.  
  12. for b := 0 to 39 do
  13.  
  14. begin
  15.  
  16. Barra := TPanel.Create(pnBarras);
  17.  
  18. Barra.Parent := pnBarras;
  19.  
  20. Barra.Name := 'Bar' + IntToStr((b + 1)); //Bar1, Bar2, Bar3, etc..
  21.  
  22. Barra.Caption := '';
  23.  
  24. Barra.ParentBackground := False;
  25.  
  26.  
  27.  
  28. case b of
  29.  
  30. 0..22: Barra.Color := clLime;
  31.  
  32. 23..34: Barra.Color := clYellow;
  33.  
  34. 35..40: Barra.Color := clRed;
  35.  
  36. end;
  37.  
  38.  
  39.  
  40. Barra.Align := alLeft;
  41.  
  42. Barra.Width := 7;// o lo que quieras
  43.  
  44. pnBarras.Width :=pnBarras.Width + Barra.Width;
  45.  
  46. //Barra.Free;
  47.  
  48. end;
  49.  
  50. end;

Y lo del Timer, prueba con esto:


delphi
  1. procedure TForm1.CambiarColores(APanel: TPanel);
  2. begin
  3. if APanel.Color = clBlack then
  4. APanel.Color := clRed
  5. else
  6. APanel.Color := clGreen; // o cualquier otra cosa que se te ocurra
  7. //Más colores, más condiciones
  8. end;
  9.  
  10. procedure TForm1.Timer1Timer(Sender: TObject);
  11. var
  12. i: integer;
  13. begin
  14. for i := 0 to pnBarras.ComponentCount - 1 do
  15. if pnBarras.Components[i].ClassType = TPanel then
  16. CambiarColores(TPanel(pnBarras.Components[i]));
  17. end;

Saludos.


  • 0

#3 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 831 mensajes
  • LocationArgentina

Escrito 21 enero 2016 - 05:42

Cuando se trata de crear controles en tiempo de ejecucion y luego necesito hacer alguna operacion con/sobre ellos, lo que suelo hacer es guardarlos en una estructura adicional: la de facto es una lista, pero bien podria ser un diccionario, un array.. lo que mas te guste / necesites

 

Esa estructura la dejo como una variable privada del form

 

Nunca me gusto lo de recorrer Controls o Components, a menos que sea para "hacer algo con todo", ya que tengo que agregar logica adicional para ver si el elemento i-esimo es el que quiero, y luego tendria que distinguirlo de otros potenciales objetos que fueron creados en diseño

 

Ademas te termina llevando a codigo como esto, el cual es super sucio:

 


delphi
  1. var
  2. I: Integer;
  3. AComponent: TComponent;
  4. APanel: TPanel;
  5. ALabel: TLabel;
  6. AButton: TButton;
  7. begin
  8. for I := 0 to ComponentCount - 1 do
  9. begin
  10. AComponent := Components[I];
  11. if AComponent is TPanel then
  12. begin
  13. APanel := TPanel(AComponent);
  14. // hacer algo con el panel
  15. end;
  16.  
  17. if AComponent is TButton then
  18. begin
  19. AButton := TButton (AComponent);
  20. // hacer algo con el button
  21. end;
  22.  
  23. // mas y mas logica..
  24. end;
  25. end;

Saludos


  • 0

#4 genriquez

genriquez

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 539 mensajes
  • LocationCali, Colombia

Escrito 22 enero 2016 - 02:16

Definitivamente la mejor estrategia es utilizar una estructura para guardar cada elemento,  usualmente las listas o diccionarios son buenísimos para eso. 

 

Igualmente para ajustar los tamaños y tener en cuenta que el panel principal puede cambiar de tamaño, si no usas alineaciones en los paneles, puedes agregar un evento en el onresize del panel principal, para recalcular  todos los tamaños de los paneles internos.

 

Saludos.


  • 1

#5 Fleon

Fleon

    Advanced Member

  • Miembros
  • PipPipPip
  • 172 mensajes
  • LocationRepública Dominicana

Escrito 23 enero 2016 - 09:22

Gracias amigo Wilson, he probado tu propuesta y sigue mostrando el espacio, cabe aclarar que el panel donde se crean los paneles tiene la propiedad Align en alCLient.

 

Fleon xDD


  • 0

#6 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14.448 mensajes
  • LocationMéxico

Escrito 23 enero 2016 - 10:02

Me parece que es un tema de porcentajes, o calculas la anchura de cada panel o calculas cuantos paneles vas a necesitar.

Hay algo que me falta en tu explicación, es por tiempo o es por algo cuantificable.

Saludos.
  • 0

#7 Fleon

Fleon

    Advanced Member

  • Miembros
  • PipPipPip
  • 172 mensajes
  • LocationRepública Dominicana

Escrito 23 enero 2016 - 10:21

En realidad necesito crear 40 paneles dentro de otro panel y que se adapten por completo sin espacio (como si se tratara de adaptar la columnas de un DBGrid) dinamicamente, y con el timer cada segundo que pase coloree los paneles creados de color negro, o sea:

 

1 segundo = coloree el panel 1

2 segundo = coloree el panel 2

y así sucesivamente.

 

Espero haberme hecho entender :( :(


  • 0

#8 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 831 mensajes
  • LocationArgentina

Escrito 23 enero 2016 - 11:25

Vamos por partes, tenes dos problemas:

 

1. Cada un segundo colorear un panel

2. Posicionamiento/redimensionamiento de los paneles

 

1. El problema 1 es facilmente solucionable con una lista:

 

Creas los paneles en tiempo de ejecucion, y los vas agregando en una lista; luego en el evento OnTimer, tomas el siguiente panel a colorear y lo pintas. Accediendo por un indice es bastante sencillo, pero te va a requerir usar una variable adicional

 

Esta implementacion la hice de memoria pero creo que deberia andar:


delphi
  1. interface
  2.  
  3. uses
  4. Generics.Collections;
  5.  
  6. type
  7. TForm1 = class(TForm);
  8. Timer1: TTimer;
  9.  
  10. procedure Timer1Timer(Sender: TObject);
  11. procedure FormCreate(Sender: TObject);
  12. procedure FormDestroy(Sender: TObject);
  13. strict private
  14. IndiceUltimoPanel: TPanel;
  15. Paneles: TList<TPanel>;
  16. end;
  17.  
  18. procedure TForm1.FomCreate(Sender: TObject);
  19. begin
  20. IndiceUltimoPanel := 0;
  21. Paneles := TList<TPanel>.Create;
  22. CrearPaneles;
  23. end;
  24.  
  25. procedure TForm1.FomCreate(Sender: TObject);
  26. begin
  27. Paneles.Free;
  28. end;
  29.  
  30. procedure TForm1.Timer1Timer(Sender: TObject);
  31. var
  32. APanel: TPanel;
  33. begin
  34. Inc(IndiceUltimoPanel);
  35. if IndiceUltimoPanel > Paneles.Count then
  36. IndiceUltimoPanel := 1;
  37.  
  38. APanel := Paneles[IndiceUltimoPanel] as TPanel;
  39. APanel.Color := clRed;
  40. end;
  41.  
  42. procedure TForm1.CrearPaneles(const APanelCount: Integer);
  43. var
  44. APanel: TPanel;
  45. I: Integer;
  46. begin
  47. for I := 1 to APanelCount do
  48. begin
  49. APanel := TPanel.Create(Self);
  50. Paneles.Add(APanel);
  51. APanel.Name := 'Panel' + IntToStr(I);
  52. // otras propiedades...
  53. end;
  54. end;


  • 1

#9 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 831 mensajes
  • LocationArgentina

Escrito 23 enero 2016 - 12:19

Como ultima recomendacion, este tipo de problemas siempre suelo encapsularlos dentro de una clase; (un pequeño off-topic (^) ) hace poco diseñe una clase similar para un programa que ya tenia que se encargaba de gestionar una lista de descendientes de una clase "Base", la cual era un descendiente de TFrame; la idea de estos frames es mostrar una pequeña ventanita con algun dibujo/pequeño listview/grafico de torta/etc con informacion estadistica, que venia de una DB

 

Entonces uno de los problemas era que tenia que existir una forma de "refrescar" cada x tiempo el contenido; por ello en la clase abstracta y padre se dispone del metodo RefreshData, entonces la solucion era, similar a la de este hilo, poner un timer y cuando se dispara el evento OnTimer, recorrer un contenedor de estos Frames e invocar al metodo RefreshData.

 

Es un monton de codigo que tiene que estar dentro del form Principal, que ya de por si tiene bastantes cosas, ahi ensuciando, hasta que decidi meterlo todo dentro de una clase. No solo que queda mas limpio, desacoplado, reusable y extensible, sino que tambien te permite tener mayor control. Por ejemplo se pueden crear eventos propios dentro de la clase, descartar un Refrescado (imaginen un evento OnBeforeRefresh)

 

Asi que cree una clase TWidgetManager, que es lo unico que paso a conocer mi Main form: toda la interaccion ahora ocurre entre propiedades, metodos y eventos. De hecho, esta clase es la que se hace cargo de controlar el Timer, y no el Form, puedo obtener una lista de todos los Widget, los Widgets "Visibles", los "Invisibles" (collapsed, que vendria a ser "contraido", y expanded); tengo un metodo Refresh publico, otro privado, puedo distinguir si es un Refresh "forzado", o uno privado (disparado por el timer), puedo invalidar un Refresh, y podria seguir agregando mas y mas funcionalidad

 

Dejo la parte interface de la clase para que se tenga un panorama mas completo..


delphi
  1. type
  2. TRefreshEvent = procedure(const IsUserRefresh: Boolean; var CanRefresh: Boolean) of object;
  3.  
  4. TWidgetManager = class
  5. strict private
  6. FWidgets: IList<TWidgetBase>;
  7. FOwnsWidgets: Boolean;
  8. FTimer: TTimer;
  9. FBeforeRefresh: TRefreshEvent;
  10. function GetWidgets: IEnumerable<TWidgetBase>;
  11. function GetExpandedWidgets: IEnumerable<TWidgetBase>;
  12. function GetCollapsedWidgets: IEnumerable<TWidgetBase>;
  13. function GetCount: Integer;
  14.  
  15. function GetRefreshInterval: Cardinal;
  16. function GetRefreshEnabled: Boolean;
  17.  
  18. procedure SetRefreshInterval(const Value: Cardinal);
  19. procedure SetRefreshEnabled(const Value: Boolean);
  20. procedure SetBeforeRefresh(const Value: TRefreshEvent);
  21.  
  22. procedure Refresh(const IsUserRefresh: Boolean); overload;
  23. procedure AutoRefresh;
  24. procedure OnTimerNotify(Sender: TObject);
  25. public
  26. constructor Create(const AOwnsWidgets: Boolean; const ARefreshInterval: Cardinal = 5000);
  27. destructor Destroy; override;
  28. function Add(AWidget: TWidgetBase): Integer;
  29. procedure Delete(const AIndex: Integer); overload;
  30. procedure Delete(AWidget: TWidgetBase); overload;
  31. procedure Refresh; overload;
  32. property Widgets: IEnumerable<TWidgetBase> read GetWidgets;
  33. property ExpandedWidgets: IEnumerable<TWidgetBase> read GetExpandedWidgets;
  34. property CollapsedWidgets: IEnumerable<TWidgetBase> read GetCollapsedWidgets;
  35. property Count: Integer read GetCount;
  36. property RefreshInterval: Cardinal read GetRefreshInterval write SetRefreshInterval;
  37. property RefreshEnabled: Boolean read GetRefreshEnabled write SetRefreshEnabled;
  38. property BeforeRefresh: TRefreshEvent read FBeforeRefresh write SetBeforeRefresh;
  39. end;

Fin off-topic :)

 

Saludos

 


  • 1

#10 Fleon

Fleon

    Advanced Member

  • Miembros
  • PipPipPip
  • 172 mensajes
  • LocationRepública Dominicana

Escrito 25 enero 2016 - 03:08

Gragias Agustín, es más hacer el recorrido de los paneles a través de una lista, todo me ha quedado perfecto, el código queda así:
 


delphi
  1. unit Unit1;
  2.  
  3. interface
  4.  
  5. uses
  6. Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  7. Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Generics.collections, Vcl.ExtCtrls;
  8. type
  9. TForm1 = class(TForm)
  10. pnBarras: TPanel;
  11. Timer1: TTimer;
  12. procedure FormCreate(Sender: TObject);
  13. procedure FormClose(Sender: TObject; var Action: TCloseAction);
  14. procedure CrearPaneles(const APanelCount: Integer);
  15. procedure Timer1Timer(Sender: TObject);
  16. private
  17. { Private declarations }
  18. public
  19. { Public declarations }
  20. strict private
  21. IndiceUltimoPanel: Integer;
  22. Paneles: TList<TPanel>;
  23. end;
  24.  
  25. var
  26. Form1: TForm1;
  27.  
  28. implementation
  29.  
  30. {$R *.dfm}
  31.  
  32. procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
  33. begin
  34. Paneles.Free;
  35. end;
  36.  
  37. procedure TForm1.FormCreate(Sender: TObject);
  38. begin
  39. IndiceUltimoPanel := 0;
  40. Paneles := TList<TPanel>.Create;
  41. CrearPaneles(40);
  42. end;
  43.  
  44. procedure TForm1.Timer1Timer(Sender: TObject);
  45. var
  46. APanel: TPanel;
  47. begin
  48. Inc(IndiceUltimoPanel);
  49. if IndiceUltimoPanel > Paneles.Count then
  50. IndiceUltimoPanel := 1;
  51.  
  52. APanel := Paneles[IndiceUltimoPanel - 1] as TPanel;
  53. APanel.Color := clBlack;
  54. end;
  55.  
  56. procedure TForm1.CrearPaneles(const APanelCount: Integer);
  57. var
  58. APanel: TPanel;
  59. I: Integer;
  60. begin
  61. for I := 1 to APanelCount do
  62. begin
  63. APanel := TPanel.Create(Self);
  64. Paneles.Add(APanel);
  65. APanel.Name := 'Panel' + IntToStr(I);
  66. APanel.Parent := pnBarras;
  67. APanel.Width := pnBarras.Width div APanelCount;
  68. APanel.Align := alLeft;
  69. APanel.ParentBackground := False;
  70. APanel.ShowCaption := False;
  71.  
  72. case i of
  73. 1..24: APanel.Color := clLime;
  74. 25..33: APanel.Color := clYellow;
  75. 34..40: APanel.Color := clRed;
  76. end;
  77. end;
  78. end;
  79.  
  80. end.

Sólo quedaría como ajustar los paneles dentro del panel contenedor, la pega que la propiedad width sólo acepta números enteros :(

Fleon xDD
  • 0

#11 genriquez

genriquez

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 539 mensajes
  • LocationCali, Colombia

Escrito 25 enero 2016 - 03:50

Pocas veces te quedarán todos los paneles del mismo ancho, si son 40 paneles, probablemente te sobrará un espacio de 39 pixeles al final en el mejor de los casos, allí toca escoger como repartir esa diferencia ente los paneles,  ej. el último panel se alinea alClient.

 

O se hace un barrido y se van sumando esas diferencias a los paneles, hasta que se completen el total o finalmente lograr que falte o que sobre un espacio y dejar un scrollbar para desplazarse.

 

y si, es que solo se pueden manejar números enteros en el ancho de cada panel.

 

Saludos.


  • 0

#12 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14.448 mensajes
  • LocationMéxico

Escrito 25 enero 2016 - 04:35

Hola

Lo que se puede hacer es definir el tamaño del Panel Maestro en un valor proporcional, por ejemplo 600, para que al momento de realizar el calculo tenga la misma proporción entre todos los paneles hijos.

Saludos


  • 0

#13 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 25 enero 2016 - 04:55

Hola

Lo que se puede hacer es definir el tamaño del Panel Maestro en un valor proporcional, por ejemplo 600, para que al momento de realizar el calculo tenga la misma proporción entre todos los paneles hijos.

Saludos

 

No he leído con mucha atención a todo el hilo. Pensé en lo mismo que vos, pero creo que esto no funciona si justo el Panel Maestro tiene una alineación definida, ya que el tamaño se adaptará a ésta. Si por tal alineación y cosas de la vida da el valor proporcional es una pura coincidencia... ¿pero y si no?

 

Saludos,


  • 0

#14 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14.448 mensajes
  • LocationMéxico

Escrito 25 enero 2016 - 05:23

No he leído con mucha atención a todo el hilo. Pensé en lo mismo que vos, pero creo que esto no funciona si justo el Panel Maestro tiene una alineación definida, ya que el tamaño se adaptará a ésta. Si por tal alineación y cosas de la vida da el valor proporcional es una pura coincidencia... ¿pero y si no?

 

Saludos,

 

Bueno es que está definido por la constante 40, la cual nos permitiría adaptar el Panel Maestro a nuestras necesidades.

 

Saludos


  • 0

#15 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 831 mensajes
  • LocationArgentina

Escrito 25 enero 2016 - 05:25

O sino se puede usar un GridPanel, y le pones la propiedad que controla el comportamiento al agregar mas elementos para que agregue columnas; siempre usarias una sola fila (la fila indice = 0)
 
Lo unico que hay que asegurarse es que el GridPanel todas las columnas esten configuradas para trabajar por porcentaje y hacer el calculo para que todas tengan el mismo valor
 
Por cierto, en el codigo que pusiste como te quedo (y cuando yo postie el mio) tenes un pequeño detalle:
 
Yo no pondria la liberacion de la lista de paneles en el evento OnClose del form; yo lo pondria en el evento OnDestroy del form (ese fue el que quise poner en mi ejemplo); aunque tambien podrias usar un destructor
 
 
De nuevo, de memoria :)

delphi
  1. TForm1 = class(TForm)
  2. FormDestroy(Sender: TObject);
  3. public
  4. destructor Destroy; override;
  5. end;
  6.  
  7. procedure TForm1.FormDestroy(Sender: TObject);
  8. begin
  9. Paneles.Free;
  10. end;
  11.  
  12. destructor TForm1.Destroy;
  13. begin
  14. Paneles.Free;
  15. inherited;
  16. end;

Cuidado! de esas dos opciones (destructor u OnDestroy) solo usar una, nunca las dos a la vez :)
  • 1

#16 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 831 mensajes
  • LocationArgentina

Escrito 25 enero 2016 - 05:29

Otro detalle bastante tonto de mi parte es este metodo:
 

delphi
  1. procedure TForm1.Timer1Timer(Sender: TObject);
  2. var
  3. APanel: TPanel;
  4. begin
  5. Inc(IndiceUltimoPanel);
  6. if IndiceUltimoPanel > Paneles.Count then
  7. IndiceUltimoPanel := 1;
  8.  
  9. APanel := Paneles[IndiceUltimoPanel - 1] as TPanel;
  10. APanel.Color := clBlack;
  11. end;

 
 
Tenemos una lista generica definida como TList<TPanel>; esto significa que la lista es type-safe, es decir, no podra haber en esta lista algo que no sea un TPanel o descendiente
 
Por lo tanto el casteo usando el operador AS en este caso no es necesario; es una operacion bastante costosa y ademas enturbia el codigo
 
El metodo correcto seria:


delphi
  1. procedure TForm1.Timer1Timer(Sender: TObject);
  2. var
  3. APanel: TPanel;
  4. begin
  5. Inc(IndiceUltimoPanel);
  6. if IndiceUltimoPanel > Paneles.Count then
  7. IndiceUltimoPanel := 1;
  8.  
  9. APanel := Paneles[IndiceUltimoPanel - 1];
  10. APanel.Color := clBlack;
  11. end;


  • 1

#17 Fleon

Fleon

    Advanced Member

  • Miembros
  • PipPipPip
  • 172 mensajes
  • LocationRepública Dominicana

Escrito 25 enero 2016 - 05:55

Hey, no se me había ocurrido el uso del TGridPanel es una excelente opción, me asalta la duda, creo las columnas y le asigno el porcentaje, perfecto, pero como colocaría los paneles en cada columna todo eso en tiempo de ejecución?.


  • 0

#18 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 831 mensajes
  • LocationArgentina

Escrito 25 enero 2016 - 06:51

Fijate de esta manera.

 

Lo unico que toque en tiempo de diseño es, del GridPanel, en la coleccion de Filas (RowCollection) elimine una, asi me queda solamente una fila

 

el resto esta todo por codigo


delphi
  1. type
  2. TForm1 = class(TForm)
  3. GridPanel1: TGridPanel;
  4. Button1: TButton;
  5. procedure FormCreate(Sender: TObject);
  6. procedure Button1Click(Sender: TObject);
  7. end;
  8.  
  9. var
  10. Form1: TForm1;
  11.  
  12. implementation
  13.  
  14. {$R *.dfm}
  15.  
  16. procedure TForm1.Button1Click(Sender: TObject);
  17. var
  18. I: Integer;
  19. APanel: TPanel;
  20. begin
  21. for I := 1 to 10 do
  22. begin
  23. APanel := TPanel.Create(GridPanel1);
  24. APanel.Parent := GridPanel1;
  25. APanel.Align := alClient;
  26. APanel.BorderStyle := bsNone;
  27. APanel.BevelOuter := bvNone;
  28. APanel.ParentBackground := False;
  29. APanel.ParentColor := False;
  30. APanel.Color := RGB(Random(255), Random(255), Random(255));
  31. end;
  32. end;
  33.  
  34. procedure TForm1.FormCreate(Sender: TObject);
  35. begin
  36. Randomize;
  37. GridPanel1.ExpandStyle := emAddColumns;
  38. GridPanel1.ShowCaption := False;
  39. end;

Salida

 

25a78472f74663914e18fe5d9230f6e3o.jpg


  • 0

#19 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 831 mensajes
  • LocationArgentina

Escrito 25 enero 2016 - 07:18

Se puede seguir mejorando la implementacion...

El problema va a ser ahora el "cuando" acomodar todo los paneles; por suerte, ahora tenemos una lista :)
 
Dentro de esta lista, tenemos acceso al evento OnNotify que se dispara cuando se produce algun cambio en la lista: agregar, quitar..
 
O mejor aun, podemos usar herencia y crear un evento que se ejecuta cuando terminamos de cargar todos los paneles; seria medio ineficiente que por cada panel que agreguemos, se ejecute todo el proceso Resize
 
La implementacion completa seria asi:


delphi
  1. unit Unit1;
  2.  
  3. interface
  4.  
  5. uses
  6.   Winapi.Windows,
  7.   Winapi.Messages,
  8.   System.SysUtils,
  9.   System.Variants,
  10.   System.Classes,
  11.   System.Generics.Collections,
  12.   Vcl.Graphics,
  13.   Vcl.Controls,
  14.   Vcl.Forms,
  15.   Vcl.Dialogs,
  16.   Vcl.ExtCtrls,
  17.   Vcl.StdCtrls;
  18.  
  19. type
  20.   TPanelList = class(TList<TPanel>)
  21.   strict private
  22.     FIsUpdating: Boolean;
  23.   strict protected
  24.     FOnFinishedUpdating: TNotifyEvent;
  25.     procedure SetOnFinishedUpdating(const Value: TNotifyEvent);
  26.     property IsUpdating: Boolean read FIsUpdating;
  27.   public
  28.     procedure BeginUpdate;
  29.     procedure EndUpdate;
  30.     property OnFinishedUpdating: TNotifyEvent read FOnFinishedUpdating write SetOnFinishedUpdating;
  31.   end;
  32.  
  33.   TForm1 = class(TForm)
  34.     GridPanel1: TGridPanel;
  35.     Button1: TButton;
  36.     procedure FormCreate(Sender: TObject);
  37.     procedure Button1Click(Sender: TObject);
  38.     procedure FormDestroy(Sender: TObject);
  39.   strict private
  40.     Paneles: TPanelList;
  41.     procedure OnPanelsUpdated(Sender: TObject);
  42.     procedure ResizeColumns(const ASizeStyle: TSizeStyle; const AValue: Double);
  43.   end;
  44.  
  45. var
  46.   Form1: TForm1;
  47.  
  48. implementation
  49.  
  50. {$R *.dfm}
  51.  
  52. procedure TForm1.Button1Click(Sender: TObject);
  53. var
  54.   I: Integer;
  55.   APanel: TPanel;
  56. begin
  57.   Paneles.BeginUpdate;
  58.   try
  59.     for I := 1 to 10 do
  60.     begin
  61.       APanel := TPanel.Create(GridPanel1);
  62.       APanel.Parent := GridPanel1;
  63.       APanel.Align := alClient;
  64.       APanel.BorderStyle := bsNone;
  65.       APanel.BevelOuter := bvNone;
  66.       APanel.ParentBackground := False;
  67.       APanel.ParentColor := False;
  68.       APanel.Color := RGB(Random(255), Random(255), Random(255));
  69.       Paneles.Add(APanel);
  70.     end;
  71.   finally
  72.     Paneles.EndUpdate;
  73.   end;
  74. end;
  75.  
  76. procedure TForm1.FormCreate(Sender: TObject);
  77. begin
  78.   Paneles := TPanelList.Create;
  79.   Paneles.OnFinishedUpdating := OnPanelsUpdated;
  80.   Randomize;
  81.   GridPanel1.ExpandStyle := emAddColumns;
  82.   GridPanel1.ShowCaption := False;
  83. end;
  84.  
  85. procedure TForm1.FormDestroy(Sender: TObject);
  86. begin
  87.   Paneles.Free;
  88. end;
  89.  
  90. procedure TForm1.OnPanelsUpdated(Sender: TObject);
  91. begin
  92.   ResizeColumns(ssAbsolute, 40);
  93. end;
  94.  
  95. procedure TForm1.ResizeColumns(const ASizeStyle: TSizeStyle; const AValue: Double);
  96. var
  97.   I: Integer;
  98.   LColumn: TCellItem;
  99. begin
  100.   for I := 0 to GridPanel1.ColumnCollection.Count - 1 do
  101.   begin
  102.     LColumn := GridPanel1.ColumnCollection[I];
  103.     LColumn.SizeStyle := ASizeStyle;
  104.     LColumn.Value := AValue;
  105.   end;
  106. end;
  107.  
  108. { TPanelList }
  109.  
  110. procedure TPanelList.BeginUpdate;
  111. begin
  112.   FIsUpdating := True;
  113. end;
  114.  
  115. procedure TPanelList.EndUpdate;
  116. begin
  117.   FIsUpdating := False;
  118.   if Assigned(FOnFinishedUpdating) then
  119.     FOnFinishedUpdating(Self);
  120. end;
  121.  
  122. procedure TPanelList.SetOnFinishedUpdating(const Value: TNotifyEvent);
  123. begin
  124.   FOnFinishedUpdating := Value;
  125. end;
  126.  
  127. end.

En el metodo resize se puede especificar por parametro el tipo de columna: por porcentaje, valor fijo (un valor constante para todas las columnas, creo que este es el que mas te sirve) y el valor en si
 
Creo que de esta manera tenes flexibilidad absoluta


  • 0

#20 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 831 mensajes
  • LocationArgentina

Escrito 25 enero 2016 - 07:18

Doble post sin querer :(
  • 0




IP.Board spam blocked by CleanTalk.