05 septiembre 2007

Mostrando información en un ListView (I)

Cuando nos conectamos a una base de datos estamos acostumbrados a mostrar la información en un componente TDBGrid, pero hay ocasiones en las que hay que mostrar información temporal que no va conectada a la base de datos. Un ejemplo sería el listar ciertos campos de los albaranes antes de facturar o procesar la información de varias tablas en una sola.

DEFINIENDO COMO SE MUESTRA LA INFORMACIÓN EN UN LISTVIEW

El componente TListView permite mostrar la información de varias maneras diferentes lo cual se especifica en su propiedad ViewStyle cuyas posibilidades son:

vsIcon -> Muestra sus elementos como iconos de tamaño normal
vsList -> Muestra sus elementos como una lista a varias columnas
vsReport -> Muestra sus elementos según las filas y columnas al estilo DBGrid.
vsSmallIcon -> Muestra sus elementos como iconos pequeños

En esta ocasión vamos a poner la propiedad ViewStyle a vsReport para que tenga un comportamiento similar a una rejilla de datos al estilo TDBGrid.

A continuación vamos a ver como definir las columnas a mostrar dentro de un ListView. Para ello lo que hacemos es hacer doble clic sobre el ListView y se abrirá una ventana para añadir columnas. Pulsando el botón Add New vamos a añadir las siguientes columnas:

Nº columna Caption Width Alignment
---------- ------------- ------ ----------------
0 Nada 0 taLeft
1 ID 50 taRightJustify
2 Artículo 150 taLeftJustify
3 Unidades 50 taRightJustify
4 Precio 50 taRightJustify
5 Total 50 taRightJustify

La primera columna de un ListView es especialmente utilizada para guardar el título de una fila o una imagen asociada como veremos más adelante. Como la primera columna que quiero mostrar es el ID y la quiero alinear a la derecha entonces no me sirve. Lo que hago es llamar a la primera columna Nada y le doy un ancho de 0 para que no se vea. Mas adelante le daremos utilidad a la misma.

Una vez definidas las columnas vamos a ver como añadir filas.

AÑADIENDO ELEMENTOS AL LISTADO

Todas las columnas que se dan de alta en un objeto ListView son de tipo String, con lo cual si deseamos mostrar otro tipo de información debemos utilizar las típicas rutinas de conversión FloatToStr, BoolToStr, etc.

Veamos un ejemplo de como dar de alta tres artículos:

procedure TFormulario.NuevoElemento;
begin
with ListView.Items.Add do
begin
SubItems.Add( '1' );
SubItems.Add( 'MONITOR LG' );
SubItems.Add( '3' );
SubItems.Add( '230,45' );
SubItems.Add( '691,35' );
end;

with ListView.Items.Add do
begin
SubItems.Add( '2' );
SubItems.Add( 'TECLADO LOGITECH' );
SubItems.Add( '2' );
SubItems.Add( '49,99' );
SubItems.Add( '99,98' );
end;

with ListView.Items.Add do
begin
SubItems.Add( '3' );
SubItems.Add( 'RATÓN OPTICO DELL' );
SubItems.Add( '5' );
SubItems.Add( '15,99' );
SubItems.Add( '79,95' );
end;
end;

Como se puede apreciar primero se crea un Item por cada fila y un SubItem para cada columna, ignorando la columna 0 donde interviene la propiedad Caption como veremos más adelante. De hecho, SubItem[0] es la segunda columna y no la primera.

MODIFICANDO LAS FILAS DEL LISTADO

El primer elemento introducido en un ListView tiene un índice de 0. Lo que vamos a hacer es cambiar el TECLADO LOGITECH por un GENIUS:

procedure TFormulario.ModificarElemento;
begin
// Modificamos el segundo elemento de la lista
with ListView.Items[1] do
begin
SubItems[1] := 'TECLADO GENIUS';
SubItems[2] := '7';
SubItems[3] := '31,99';
SubItems[4] := '223,93';
end;
end;

Hemos cambiado todos las columnas menos la primera (el ID). Aquí hay que andarse con ojo y no acceder a un elemento de que no exista porque si no provocaría el error que tanto nos gusta:

Access violation at address ....


ELIMINANDO FILAS DE LA LISTA

Eliminar un registro de la lista es algo tan secillo de hacer como:

ListView.Items[0].Delete;

Eso elimina la primera fila. Y si deseamos eliminar todos los elementos de la lista:

ListView.Items.Clear;

CAMBIANDO EL ASPECTO Y EL COMPORTAMIENTO DEL LISTADO

En la lista que hemos creado no podemos seleccionar ninguna fila, esta algo así como bloqueado. Para poder hacerlo hay que activar la propiedad RowSelect a True.

Otra característica interesante es la de mostrar un separador de filas y columnas al estilo de la rejilla DBGrid. Para ello activa la propiedad GridLines a True.

También ocurre que si tenemos una fila seleccionada y pasamos el foco a otro control parece que se pierde la selección de dicha fila, aunque realmente sigue seleccionada si volvemos al mismo. Para evitar esto lo que debemos hacer es desactivar la propiedad HideSelection de tal manera que cuando pasemos a otro control en vez de estar la fila seleccionada en azul lo hace en color gris pero sigue estando seleccionada para el usuario.

Y si queremos seleccionar más de una fila activamos la propiedad Multiselect, de tal manera que si hay una fila seleccionada puede saberse de la siguiente manera:

if ListView.Selected <> nil then
...

Siendo Selected el Item de la lista que ha sido seleccionado.

Si hay muchas seleccionadas la propiedad SelCount nos lo dirá el número de filas seleccionadas en todo momento. Para averiguar que filas están seleccionadas lo que hacemos es recorrer la lista y ver aquellos elementos que tienen a True la propiedad Selected:

procedure TFormulario.VerSeleccionados;
var
Seleccionados: TStringList;
i: Integer;
begin
Seleccionados := TStringList.Create;

for i := 0 to ListView.Items.Count - 1 do
if ListView.Items[i].Selected then
Seleccionados.Add( ListView.Items[i].SubItems[1] );

ShowMessage( Seleccionados.Text );

Seleccionados.Free;
end;

Lo que hace este procedimiento es crear un objeto StringList y volcar dentro del mismo el nombre de los artículos seleccionados para después sacarlo por pantalla.

En el próximo artículo seguiremos viendo que más cosas se pueden hacer con un ListView.

Pruebas realizadas en Delphi 7.

7 comentarios:

Anónimo dijo...

Muy buena informacion se le agradece de antamano, Gracias.

José Torres dijo...

Tu serie de artículos es invalorable, te los agradezco mucho. Más de una vez me han sacado de un apuro, están bien redactados y organizados, es un placer leerlos. Muchas gracias!

Administrador dijo...

Me alegro de que aprovechéis la información que recopilo al igual que yo.

No hay que parar de aprender cosas nuevas.

Saludos.

Antonio Espinosa dijo...

muchas felicidades esta muy completo tu articulo, pero aun tengo una duda si es posible que me ayudes a resolver, quiero seleccionar un subitem del listview para modificarlo desde el teclado

muchas gracias, espero mas articulos como este.

exito!

Unknown dijo...

Por que si coloco la propiedad MultiSelect en true, no logro ver el caption del primer elemento de la lista.

Unknown dijo...

Sabes por que no aparece el texto del primer elemento si coloco true a la propiedad multiselect. Si lo quito veo el texto perfecto.

Carlos Ramirez dijo...

HOLA MCUAS GRACIAS POR ESTE MARAVILLO MATERIAL, ESPERO SIGAS PUBLICANDO MAS COSAS

Publicidad