Este artículo está dividido en dos partes.
La primera está destinada para los que yo llamo pintores: aquellos que buscan nuevas mejoras para aplicar a sus programas y quieren aprender a utilizarlas, pero les dá igual cómo funcionan por dentro.
La segunda parte está destinada a los fabricantes de pinceles, que son los que están más interesados en cómo se construye la herramienta que en su uso definitivo.
Funcionamiento de los browses elásticos.
Lo primero será añadir un ArrayBrowse a nuestro formulario y cambiar la propiedad nAnchors a akTOPLEFTRIGHT.
Luego, completaremos es ArrayBrowse añadiendo las columnas necesarias.
Ya sólo nos queda añadir un puñado de líneas al dentro del programa
Nos creamos dos nuevos métodos Cargadatos() y ArrayBrowse1onsize() dentro de la definición de la clase
CLASS TForm1 FROM TForm
COMPONENT oArrayBrowse1
COMPONENT oArrayBrowse2
COMPONENT oArrayBrowse1Column5
COMPONENT oLabel1
COMPONENT oLabel2
METHOD CreateForm()
METHOD FormShow( oSender )
METHOD ArrayBrowse1onsize( oSender )
METHOD ArrayBrowse1Create( oSender )
METHOD Cargadatos()
ENDCLASS
En el evento OnCreate del ArrayBrowse indicaremos lo siguiente
oSender:aCols[2]:nPorcien := 25
oSender:aCols[3]:nPorcien := 50
oSender:aCols[4]:nPorcien := 25
// -------
// 100%
Donde le estamos diciendo al browse el % de la anchura de cada colunma elástica.
Las columnas 1 y 5, son de anchura fija, por lo cual no hace falta modificar la propiedad nPorcien
Ahora le definimos a la columna 2 una anchura mínima de 200 pixel. Si al cambiar de tamaño el browse, la columna 2 tiene una anchura menor de 200, la ocultará automáticamente.
oSender:aCols[2]:nMinlen := 200
Por último, alimentamos el valor del evento OnSize del browse para que se ejecute en método ArrayBrowse1onsize
oSender:OnSize := "ArrayBrowse1onsize"
En ArrayBrowse1onsize nos limitamos a llamar al método Pintar() del ArrayBrowse, que es el encargado de recalcular el tamaño de las columnas y mostrarlas dentro del browse
METHOD ArrayBrowse1onsize( oSender ) CLASS TForm1
oSender:Pintar( oSender )
retu nil
Por último, en el evento FormShow del formulario llamamos a CargaDatos(), para que rellene los valores del ArrayBrowse al mostrar el formulario
METHOD FormShow( oSender ) CLASS TForm1
::CargaDatos()
RETURN Nil
Listo!, dale al play y a funcionar.
Si eres del tipo de los pintores, esto es todo amigo, ya hemos terminado.
Si eres de los fabricantes de pinceles, continúa leyendo, que te interesa lo que viene.
Para lograr nuestro efecto «elástico» en el ArrayBrowse, no he hecho otra cosa que jugar con dos de las clases de Xailer: TBrwColumn y TArrayBrowse.
Modificaciones a TBrwColumn
CLASS TBrwColumn FROM XBrwColumn
PUBLISHED:
PROPERTY nPorcien INIT 0
PROPERTY nMinLen INIT 0
PROTECTED:
DATA nInitWidth
PUBLIC:
METHOD Create( oParent ) CONSTRUCTOR
ENDCLASS
Le he añadido 3 propiedades nuevas
nPorcien: % que tiene que ocupar cada una de las columnas elásticas dentro del browse. Las columnas con nPorcien=0 se comportan como las columnas de toda la vida
nMinLen: Tamaño mínimo de la columna a partir del cual la ocultaremos.
nInitWidth: Tamaño inicial de la columna
La propiedad nInitWidth la usa internamente el programa y guarda el tamaño inicial de cada columna. Es muy importante para el correcto funcionamiento de la clase que este dato no se pueda modificar desde fuera de la definición de la clase, por eso la hemos declarado como DATA Y PROTECTED.
Así, si intentamos hacer ::oArraybrowse1:aCols[4]:ninitWidth := 25 desde nuestros programas, Xailer nos dará un error.
Para poder guardar el valor de nInitWidth tenemos que sobrecargar el evento OnCreate de la clase, para ello, nos creamos nuestro propio método Create modificado
METHOD Create( oParent ) CLASS TBrwColumn
super:Create( oParent )
::nInitWidth := ::nWidth
RETURN Self
Lo primero que hacemos es super:Create( oParent ), o sea, ejecutar el create de la clase original (XBrwColumn) para que genere el objeto correspondiente a cada columna.
Una vez creada la columna, guardamos el valor que tiene nWidth en ese momento, cuando aún no hemos empezado a jugar con la anchura de la columna
La segunda clase que he modificado es TArrayBrowse
Al igual que a TBrwColumn, le he añadido la propiedad nInitWidth, que guardará el tamaño original del browse.
CLASS TArrayBrowse FROM XArrayBrowse
PROTECTED:
DATA ninitwidth
PUBLIC:
METHOD Create( oParent ) CONSTRUCTOR
METHOD WMSize( nWParam, nLParam )
METHOD Pintar( oSender )
METHOD Porcion( nPixels, nPorcien )
EVENT OnSize( oSender, nSizeType, nClientWidth, nClientHeight )
ENDCLASS
Además, he sobrecargado el método Create, he añadido dos métodos nuevos (pintar y porción) y he creado el evento OnSize, que inicialmente no existe en la clase TArrayBrowse.
Vamos a empezar por esto último, que personalmente es lo que más me ha llamado la atención.
Como ya hemos visto, en la definición de la clase preparamos el método WMSize y el evento OnSize
Luego, en el desarrollo de la clase en sí, basta con poner:
METHOD WMSize( nWParam, nLParam ) CLASS TArrayBrowse
::OnSize( nWParam, LoWord( nLParam ), HiWord( nLParam ) )
RETURN Super:WMSize( nWParam, nLParam ) )
Y listo. No explico más de este método porque tamposo sé mucho más, ha sido Ignacio el que me ha dicho cómo hacerlo. Yo me he limitado a copiar y pegar.
El segundo paso es sobrecargar el método create.
METHOD Create( oParent ) CLASS TArrayBrowse
super:Create( oParent )
::nInitWidth := ::nWidth
::Pintar( Self )
RETURN Self
Al igual que hemos hecho antes en TBrwColumn, llamamos al create original, cargamos nInitWidth y, en este caso, llamamos al método pintar() para que nos dibuje por primera el browse elástico.
De los dos métodos que nos quedan, porcion() se encarga de calcular y traducir el ancho de la columna de porcentaje a pixels
METHOD Porcion( nPixels, nPorcien ) class TArrayBrowse
RETURN nPixels * ( nPorcien / 100 )
Pintar() contine el corazon de la modificacion.
METHOD Pintar( osender ) CLASS TArrayBrowse
Local nColumnas := Len( oSender:aCols )
Local nResto := oSender:nWidth - oSender:nInitWidth
Local nPorcienOcultas := nAnchoOcultas := nColVisibles := 0
Local n,a
nColumnas: cuántas columnas tiene el browse
nResto: El tamaño actura del browse menos el tamaño inicial, esto es, los pixels que nos sobran del browse y que hay que rellenar.
nPorcienOcultas: En caso de que una columna esté oculta, el % de la anchura de la misma, que luego tendremos que repartir entre las columnas visibles.
nAnchoOcultas: suma de la anchura inicial de las columnas ocultas.
nColVisibles : Número de columnas elásticas dentro del browse
Lo primero es saber cuántas columnas tenemos que mostrar y de qué anchura.
Para ello:
Nos metemos en un bucle por cada una de las columnas Si es una columna elástica (nPorcien > 0) A la anchura inicial de la columna le sumamos los pixels correspondientes al % que ocupa la columna de la parte que nos sobra del browse (nResto) Si el resultado es menor que el nMinLen de la columna, la ocultamos. Acumulamos la anchura y el porcentaje de la columna oculta.como no se muestra,luego tendremos que repartir estos valores entre las columnas visibles Si la columna es visible Incrementamos el contador de columnas visibles
FOR n := 1 TO nColumnas
IF oSender:aCols[n]:nPorcien > 0
a := oSender:aCols[n]:nInitWidth + ;
oSender:Porcion( nResto, oSender:aCols[n]:nPorcien )
IF !oSender:aCols[n]:lVisible := a > oSender:aCols[n]:nMinLen
nAnchoOcultas += oSender:aCols[n]:nInitWidth
nPorcienOcultas += oSender:aCols[n]:nPorcien
ELSE
nColVisibles ++
ENDIF
ENDIF
NEXT
Ahora ya sabemos:
-Cuántas columnas hay visibles ( nColVisibles)
-La suma del tamaño en pixels y el porcentaje que ocupan las columnas ocultas (nAnchoOcultas y nPorcienOcultas)
Nuestro siguiente paso será repartir el % que ocupan las columnas ocultas entre las columnas que son visibles, para que las columnas visibles ocupen el 100% del browse
nPorcienOcultas := nPorcienOcultas / Max( nColVisibles , 1 ) // % a añadir a cada columna visible
También tenemos que sumar al espacio libre del browse el tamaño de las columnas que no se van a mostrar
nResto := nResto + nAnchoOcultas
Ahora que ya sabemos las columnas que se van a mostrar y el espacio que nos queda libre, tan solo tenemos que ajustar cada columna a su tamaño.
Por cada columna Si es elástica anchura := su anchura original + los pixel que corresponden a su porcentaje + el porcentaje extra de las columnas ocultas (nPorcienOcultas)
FOR n:= 1 TO nColumnas
IF oSender:aCols[n]:nPorcien > 0
oSender:aCols[n]:nWidth := oSender:aCols[n]:nInitWidth + ;
oSender:Porcion( nResto, oSender:aCols[n]:nPorcien + nPorcienOcultas )
ENDIF
NEXT
Y eso es todo, ni más ni menos.
Lo mismo que he hecho para el TArrayBrowse se puede hacer con el resto de browse.
Por último he de confesar que me considero pintor antes que fabricante de pinceles, así que, tiro la piedra y escondo la mano.
A ver si algún maestro de Xailer se anima y crea una colección de controles «ElasticBrowse»
El código fuente lo tenéis en la sección de descargas
Fredy,
muy, muy bueno. Muchas gracias por compartirlo.