Grids Reference Page/es

From Lazarus wiki
Revision as of 14:49, 30 September 2015 by Jma sp (talk | contribs) (Procedimiento AutoSizeColumn(aCol: Integer);)

Deutsch (de) English (en) español (es) polski (pl) русский (ru)

Contents

Objetivo

Este texto trata de enseñar al usuario algunos aspectos de los componentes tipo grid ("rejilla" por traducirlo de alguna forma). También tiene el propósito de servir de guía para usuarios que nunca hayan utilizado grids con anterioridad (los usuarios experimentados generalmente solo necesitan las referencias sobre nuevas funcionalidades). Por lo tanto este documento tratará de conseguir los siguientes objetivos:

  1. Servir de introducción a los componentes tipo grid para la gente que tenga pocos o ningún conocimiento previo de Lazarus.
  2. Documentar las diferencias con respecto a los componentes tipo grid utilizados en Delphi.
  3. Documentar la nueva funcionalidad de las grids en Lazarus.
  4. Crear referencias y ejemplos para estos componentes.

Descripción

Una grid es un componente que aporta un significado para los datos mostrados en un formato tabulado (tabla). La característica más obvia de las grids es que están compuestas por celdas (cells) formando filas (rows) y columnas (cols).

El tipo de información que pueden mostrar es muy amplio y mayoritariamente depende de lo que el usuario necesita mostrar. Generalmente esta información consiste en texto, colores, imágenes o una combinación de estos tres.

Dada la gran variedad de información que pueden representar, se ha creado una serie de grids más específicas dependiendo del tipo de información a mostrar. Por ejemplo existe un tipo de grid para mostrar texto, StringGrid, de la cual podemos encontrar documentación aquí

El siguiente diagrama muestra el árbol de herencia con los tipos existentes:

Árbol de herencia

diagrama grids.png

Un ejemplo inicial

Como uno de los objetivos de ésta página es ayudar a la gente con poco o ningún conocimiento previo de Lazarus, nos vamos a permitir poner un breve ejemplo como punto de partida para entender las grids en acción. Porque no, hagamos un tradicional "¡ Hola Mundo !" como ejemplo del uso del componente TStringGrid.

  1. Crear una nueva aplicación.
    • Desde el menú principal seleccionar: Archivo -> Nuevo ... -> Proyecto -> Aplicación.
    • Una vez selecciona Aplicación pulsamos Aceptar.
    • Nos muestra un formulario (Form1) vacío nuevo.
  2. Situar una grid (rejilla) sobre el formulario Form1.
    • Desde la paleta de componentes seleccionar la solapa "Additional".
    • Hacer Click sobre el icono TStringGrid [].
    • Hacer Click sobre el formulario, cerca de la esquina superior izquierda. De esta forma aparece una grid nueva vacía.
  3. Situar un pulsador (button) en el formulario.
    • Desde la paleta de componentes seleccionar la solapa "Standard".
    • Hacer Click sobre el icono TButton [].
    • Hacer Click sobre un área vacía del formulario. De esta forma aparece un nuevo pulsador(button).
  4. Hacer doble click sobre el pulsador del paso 3 y donde sitúa el cursor parpadeante (código para el manejador (handler) del pulsador) escribir el siguiente fragmento de código.
    • Stringgrid1.Cells[1,1] := '¡ Hola Mundo !';
    • Ejecuta el programa haciendo Click en el icono de play [].
  5. Una vez que compila correctamente el programa aparece el formulario con un pulsador, pues bien, si hacemos Click sobre el pulsador "button1" deberíamos visualizar ¡ Hola Mundo ! en la celda que hemos especificado en este caso la correspondiente a la fila 1 y columna 1.

Diferencias entre las grids de Delphi y las de Lazarus

Los componentes tipo grid actuales de Lazarus presentan varias diferencias con respecto a las disponibles en Delphi. Esto se debe principalmente a que las grids de Lazarus fueron creadas desde cero y no se buscaba que tuviesen una total compatibilidad con las de Delphi,

Posteriormente, se puso como objetivo tener dicha compatibilidad y las grids se empezaron a diseñar lo más parecidas al interface que tienen en Delphi, pero incluso cuando esto se empezó a implementar así tampoco se realizó un excesivo esfuerzo para hacer coincidir cada propiedad equivalente en Delphi.

También, debido a que el desarrollo interno de las grids es muy diferente, algunos aspectos no son posibles o necesitan realizarse de un modo diferente en Lazarus. Además (debido a que las grid de Lazarus internamente son muy diferentes a las de Delphi)algunas funcionalidades de Delphi no son posibles o necesitan ser emuladas de una manera diferente en las grids de Lazarus. De todas formas se ha alcanzado un alto grado de compatibilidad, lo cual es deseable.

Diferencias

Las siguientes son diferencias evidentes:

  • Editores de celdas (Cell).
  • Comportamiento en tiempo de diseño.
  • El dibujo de las celdas tiene algunas diferencias, ver la sección de personalización de grids para más detalles.

Nuevas funcionalidades

  • Columnas personalizadas.
  • Eventos.
  • Editor de Grid.

Ajustes para afianzar la compatibilidad con grids de Delphi

Aquí hay una lista de propiedades y ajustes que se pueden realizar para lograr que las grids de Lazarus se parezcan o comporten de modo similar la las de Delphi. Estos ajustes están basados en una nueva grid creada. Las entradas etiquetadas con [code] necesitan establecerse con código, mientras que las etiquetadas como [Design] pueden modificarse en tiempo de diseño.

  • [Design] TitleStyle := tsStandard;
  • [Design] DefaultRowHeight := 24;
  • [Code] EditorBorderStyle := bsNone; // esto debería funcionar únicamente en windows.
  • [Code] UseXORFeatures := true;
  • [Code] AllowOutBoundEvents := False; {r10992 o posterior}
  • [Code] FastEditing := False; (soportado en dbgrid. StringGrid req. r10992 o posterior)
  • [Design] AutoAdvance := aaNone;

Referencia de Grids

Información

El punto de partida para referencias sobre TCustomGrid, TDrawGrid, TCustomDrawGrid, TCustomStringGrid y TStringGrid es: Referencia unit Grids.pas

Para TCustomDBGrid y TDBgrid es: Referencia: unit DBGrids.pas

Hasta hace poco no había demasiado contenido en estos enlaces, debido en parte a la carencia de utilidades que permiten mantener facilmente su contenido: pero finalmente estas herramientas han sido creadas y se ha llenado el vacio de contenido que tenían.

En general, cualquier referencia Delphi acerca de las grids deberían ayudar en el uso de las equivalentes de Lazarus (pero no no se debe olvidar que existen algunas diferencias tal como se ha indicado); con esto en mente y como un lugar temporal de referencia de información, este espacio se utilizará para documentar cosas que no funcionan de igual manera en Delphi, aparte de las nuevas funcionalidades de las existentes en Lazarus.


Cosas por hacer: el resto de esta sección desaparecerá. Su contenido se trasladará a Referencia: unit Grids.pas

TCustomGrid

Ver la Referencia: TCustomGrid

Propiedad AllowOutboundEvents

Protegida en TCustomGrid, pública en TCustomDrawGrid y descendientes. Normalmente cuando un usuario hace click en un punto sobre el espacio vacío después de las celdas (por ejemplo si la grid tiene tres filas pero el usuario hace click sobre una cuarta línea imaginaria), el foco actual se mueve a la celda más cercana a este punto. Llamamos a esto un evento outbound. El valor por defecto de esta propiedad está establecido a True tal como se estableció desde el principio del comportamiento de las grid. Esta propiedad se ha añadido para simular el comportamiento de Delphi donde los eventos outbound no están disponibles, por lo que para habilitar su compatibilidad con Delphi se debe establecer esta propiedad a falso.

Propiedad Columns

Lazarus incluye la propiedad columns' en las grid tipo TStringGrid y TDrawGrid. Esta propiedad añade lo que llamamos columnas personalizadas. Las columnas personalizadas son una colección de objetos con propiedades que se aplican al conjunto completo de columnas que contiene la grid, por ejemplo títulos de las columnas (para una StringGrid sobreescribirá el valor especificado en las propiedades [ColumnIndex, RowTitle] correspondientes de las celdas, alineación de texto, color de fondo, etitor preferido, etc.

Las columnas personalizadas añaden propiedades extra o reemplazan los valores por defecto de las propiedades en las columnas de la grid normal. No solamente esto, el valor grid.ColCount puede incrementarse o decrementarse para contabilizar el numero de columnas personalizadas añadidas a la grid. En este punto, esto significa grid.ColCount = grid.FixedCols + grid.Columns.Count.

Por ejemplo, si a una grid base con with ColCount := 5 y FixedCols := 2 hacemos:

  • Añadir 3 columnas personalizadas, la grid base estará exactamente como antes, 2 columnas fijas y 3 columnas normales.
  • Añadir una columna personalizada, la grid base tendrá ColCount := 3, esto es 2 columnas fijas y una columna normal.
  • Añadir 4 columnas personalizadas, la grid base tendrá ColCount := 6, esto es 2 columnas fijas y 4 columnas normales.

Por tanto podemos concluir que:

  • Las propiedades de columnas fijas o su cuenta no son afianzadas o modificadas respectivamente por las columnas personalizadas.
  • grid.ColCount es usualmente diferente de grid.Columns.Count (grid.ColCount=grid.Columns.Count solamente cuando FixedCols=0).

En tiempo de diseño el usuario puede acceder a las propiedades de columns mediante el Inspector de Objetos para arrancar el editor de columnas. Desde él, se pueden añadir, eliminar o modificar las columnas personalizadas. El editor muestra una lista de las columnas personalizadas mediante la selección de elementos en el listado que nos ofrece el inspector de objetos con las propiedades rellenas para cada columna. El listado de las columnas personalizadas se encuentra también disponible en la vista en árbol de componentes del Inspector de Objetos, donde se pueden añadir, borrar o modificar columnas. Aparecen a un menor nivel bajo la grid (regilla) contenedora.

En tiempo de ejecución, las columnas se pueden modificar con un código como este:

  var
    c: TGridColumn;
  begin
    // Añade una columna personalizada a la grid
    c := Grid.Columns.Add;
    // La modifica
    c.title.caption := 'Precio';       // Establece el valor caption de la columna.
    c.align := taRightJustify;         // Alinea a la derecha el contenido de la columna.
    c.color := clMoneyGreen;           // Cambia el valor por defecto a clMoneyGreen.
    c.Index := 0;                      // La hace la primera columna.
    // Accede a una columna existente
    grid.columns[0].Width := 60;       // Cambia el ancho de la columna 0 a 60 pixeles.
    // Elimina una columna existente.
    grid.columns.delete(0);            // Elimina la columna 0
    ....
  end;

Adicionalmente, cuando se utilizan columnas personalizadas, las grids no permiten la modificación directa de grids.colcount; añadir o eliminar columnas se debería hacer utilizando la propiedad columns. La explicación es que hay una inconsistencia al remover gradualmente las columnas personalizadas mediante el uso de ColCount, cuando ColCount llega a FixedCols, la grid no tiene más columnas personalizadas. Si en ese momento incrementamos ColCount, la nueva columna no será del tipo personalizado sino una columna normal.

Actualmente no hay planes para hacer que las grids utilicen únicamente columnas personalizadas.

TCustomDBGrid

TCustomDBGrid es la base para TDBGrid.

No exponen las propiedades Col y Row. Para ir a una determinada columna, utilizar e.g. la propiedad SelectedIndex.

Un método público interesante es AutoSizeColumns.

Procedimiento AutoSizeColumns

Este procedimiento establece el ancho (width) al tamaño que abarque el ancho mayor del texto que encuentre. Esto se puede utilizar después de cargar un dataset estableciéndolo a Activo. Sin embargo, contrariamente a TCustomStringGrid.AutoSizecolumns (ver más abajo), esto establecerá tus columnas muy anchas a menos que tengas habilitada la propiedad dgAutoSizeColumns.

Procedimiento InplaceEditor

Ver ejemplo del bug 23103 - e inserta explicación de lo que hace y porque se necesita. ¿Validar valores de entrada? ¿Cambiar lo que se muestra?

procedure TForm1.DBGrid1KeyPress(Sender: TObject; var Key: char);
var
  S: String;
begin
  if (Key in [',','.']) then
  begin
    //Al contrario que Delphi no todos los InPlaceEditors son editores para el tipo string, por tanto verificalo.
    if (DBGrid1.InplaceEditor is TStringCellEditor) then
    begin
      S := TStringCellEditor(DBGrid1.InplaceEditor).EditText;
      if Pos(',',S) > 0 then
        Key := #0
      else
        Key := ',';
    end;
  end;
end;

TCustomStringGrid

TCustomStringGrid sirve como base para TStringGrid. Se puede utilizar para componentes derivados TStringGrid que necesiten ocultar propiedades publicadas. Ver new intermediate grids para más información.

Las siguientes propiedades o métodos son públicos y están además disponibles para TStringGrid.

Ver la referencia completa para TCustomStringGrid

Procedimiento AutoSizeColumn(aCol: Integer);

Este procedimiento establece el ancho de columna de forma sea suficiente para contener el tamaño del texto más largo que encuentre en todas las filas de la columna aCol. Consejo: ver la opción goDblClickAutoSize para permitir a las columnas redimensionarse automáticamente cuando se realiza el dobleclick en el borde de la columna.

Procedimiento AutoSizeColumns;

Redimensiona automáticamente todas las columnas ajustándolas para que quepa el texto más ancho en cada columna. Este es un método rápido de aplicar AutoSizeColumn() para todas las columnas de la grid.

Procedimiento Clean; overload;

Limpia todas las celdas de la grid, fijas o no fijas.

Procedimiento Clean(CleanOptions: TGridZoneSet); overload;

Limpia todas las celdas en la grid sujetas a lo establecido en CleanOptions. Ver TGridZoneSet para mas información. Algunos ejemplos:

  • Limpia todas las celdas: grid.Clean([]); (lo mismo que grid.clean)
  • Limpia todas las celdas no fijas: grid.Clean([gzNormal]);
  • Limpia todas las celdas salvo no toca las cabeceras de las columnas: Grid.Clean([gzNormal, gzFixedRows]);

Procedimiento Clean(StartCol,StartRow,EndCol,EndRow: integer; CleanOptions:TGridZoneSet); overload;

Hace lo mismo que Clean(CleanOptions:TGridZoneSet) pero restringiéndolo a lo siguiente StartCol,StartRow,EndCol y EndRow, por tanto acota el contenido a limpiar estableciendo tanto columna como fila de inicio y columna y fila final inclusive. Ejemplos:

  • Limpia las columnas de indice 4 hasta 6 pero no toca las cabeceras de columna de la grid: algunas variaciones, Grid.Clean(4,Grid.FixedRows,6,Grid.RowCount-1,[]); Grid.Clean(4,0,6,Grid,RowCount-1, [gzNormal]); etc.

Procedimiento Clean(aRect: TRect; CleanOptions: TGridZoneSet); overload;

Lo mismo que Clean(StartCol,StartRow,EndCol,EndRow, CleanOptions), pero tomando un rectánguno TRect seleccionado en lugar de coordenadas de celdas indivisutales. Útil para limpiar la selección: grid.Clean(Grid.Selection,[]);

Procedimiento SaveToCSVFile(AFileName: string; ADelimiter:Char=','; WithHeader:boolean=true);

Salva el contenido de la grid a un fichero con formato CSV (Comma Separated Values) conteniendo valores separados por comas (añadido en Lazarus r32179).

El argumento AFilename especifica el nombre de fichero en el que se salvará el contenido. Si el fichero existe, se sobreecribe su contenido. Caso de no existir previamente el fichero se crea.

Se utiliza ADelimiter (como argumento opcional) para que utilice un separador personalizado en lugar de comas. Por defecto se genera un formato CSV (esto es, ADelimiter:=',';), para poner como separador un tabulador ADelimiter debería valer #9, correspondiente a TAB.

Para decidir si se incluye una "fila de cabecera" o no, se utiliza el parámetro WithHeader. La fila de cabecera es un listado de nombres de campos al comienzo del fichero de salida; su contenido procede de la última fila fija de la grid.

Hay una excepción a esta regla: si la grid tiene columnas personalizadas entonces el contenido de la fila de cabecera procede de los títulos de las columnas personalizadas y no del contenido de las celdas de la fila fija.

Si WithHeader vale true y la grid no incluye una fila fija o columnas personalizadas, entonces se toma el contenido del la ficha de cabecera desde la primera fila que se encuentra en la grid.

Los datos normales de salida CSV deben comenzar en la primera fila no fija de la grid.

Procedimiento LoadFromCSVFile(AFileName: string; ADelimiter:Char=','; WithHeader:boolean=true);

Carga el contenido de la grid desde un fichero con formato de valores separados por coma (CSV) (añadido en Lazarus r32179).

Las columnas serán añadidas o borradas a o desde la grid según se necesite de acuerdo al número de campos incluidos en cada línea del fichero CSV. Realizar la carga desde un fichero CSV no modificará el número de filas fijas que ya existan en la grid.

El argumentoAfilename especifica el nombre de fichero con el contenido CSV.

ADelimiter optional parameter may be used to specify a different separator or delimiter. An example: for a tab-separated file, ADelimiter should be #9. Another popular file format is semicolon-delimited file, where ADelimiter should be ;

El parámetro WithHeader se utiliza para decidir si la primera línea en el fichero CSV se considera como la "cabecera de fila" o no. Si la grid tiene filas fijas y WithHeader vale true, entonces los captions de la columna de la última fila fija se utomarán de la fila de cabecera. Ten en cuenta de todas forma que si la grid tiene columnas personalizadas, entonces la fila de cabecera se utilizará como fuente para los títulos columna y los títulos de las columnas personalizadas se muestran siempre en la primera fila fija u oculta si no existen filas fijas en la grid.

Si el procedimiento LoadFromCSVFile presenta dificultades para cargar el fichero CSV (e.g. comillas o espacios interpretados incorrectamente), entonces puedes realizar la carga manualmente utilizando e.g. CsvDocument... y por supuesto un parche para LoadFromCSVFile es siempre bienvenido.

Propiedad Cols[index: Integer]: TStrings lee GetCols escribe SetCols;

Obtiene/establece un listado de cadenas desde/hacia la columna índice de la grid comenzando desde la fila índice 0 hasta RowCount-1.

Ejemplos
  • Ejemplo para establecer: Establece el contenido de la tercera columna en la grid desde una ListBox
Grid.Cols[2] := ListBox1.Items;
  • Ejemplo para obtener: Establece el contenido de un Listbox desde la columna índice 4 de la grid.
procedure TForm1.FillListBox1;
var 
  StrTempList: TStringList;
begin
  StrTempList := TStringList(Grid.Cols[4]);
  if StrTempList<>nil then 
  begin
    ListBox1.Items.Assign(StrTempList);
    StrTempList.Free;
  end;
end;
Notas.

Esta propiedad funciona de una manera diferente en Lazarus respecto a Delphi cuando obtiene datos desde la grid.

En Lazarus se crea un objeto temporal del tipo TStringList para obtener el contenido. Es responsabilidad del usuario liberar los recursos de este objeto después de su uso.

Esto significa además que los cambios en el listado retornado no afectaran al contenido de la grid o su disposición.

Ver el ejemplo "obtener".

property Rows[index: Integer]: TStrings read GetRows write SetRows;

Get/set a list of strings from/to the given grid's row index starting from column index 0 to column ColCount-1.

Notas.

Esta propiedad funciona de forma diferente en Lazarus que en Delphi cuando se cogen datos de la grid. En Lazarus se crea un objeto temporal tipo TStringList para recabar el contenido de la fila. Es responsabilidad del usuario liberar este objeto después de finalizar su uso. Esto significa también que los cambios en el listado retornado no afectarán al contenido de la grid o su disposición.

Ejemplos
  • Ejemplo para establecer: Establece el contenido de la tercera fila en la grid desde una ListBox:
Grid.Rows[2] := ListBox1.Items;
  • Ejemplo para obtener: Establece el contenido de una Listbox desde la columna índice 4 de la grid:
procedure TForm1.FillListBox1;
var 
  StrTempList: TStringList;
begin
  StrTempList := TStringList(Grid.Rows[4]);
  if StrTempList<>nil then 
  begin
    ListBox1.Items.Assign(StrTempList);
    StrTempList.Free;
  end;
end;
  • Un ejemplo que no funciona, y su solución: El listado de cadenas es de solo lectura.
// Esto no funcionará y causará una pérdida de memoria.
// porque el StringList retornado no se libera.

Grid.Rows[1].CommaText := '1,2,3,4,5';
Grid.Rows[2].Text := 'a'+#13#10+'s'+#13#10+'d'+#13#10+'f'+#13#10+'g'; 
 
// Solucionando el primer caso.

Lst:=TStringList.Create;  // Crea el StringList asignándole recursos de memoria.
Lst.CommaText := '1,2,3,4,5';
Grid.Rows[1] := Lst;
Lst.Free; // Libera los recursos de memoria asignados a StringList cuando ya no lo necesitamos.

Propiedad UseXORFeatures;

Propiedad booleana, su valor por defecto es False;

Esta propiedad controla como aparece en la grid el rectángulo punteado de foco. Cuando vale true, el rectángulo se pinta utilizando la operación de rasteado XOR. Esto nos permite ver el rectángulo de focus sin preocuparnos del color de fondo que tengan las celdas. Cuando vale false, el usuario puede controlar el color del rectángulo punteado del foco utilizando la [[FocusColor property] Propiedad Focus Color].

Esto controla además el aspecto del redimensionado fila/columna. Cuando vale true una línea muestra visualmente el tamaño que tendrá la fila o la columna si el usuario finaliza la operación. Cuando vale false, entonces el redimensionado de la fila o la columna tendrá efecta tal como el usuario arrastre el ratón.

TValueListEditor

TValueListEditor es un control derivado de TCustomStringGrid para edición de pares Key-Value.

Propiedad DisplayOptions

Controla varios aspectos de la aparariencia de TValueListEditor.

Propiedad TitleCaptions

Establece los valores de los captions del título (si doColumnTitles se encuentra en DisplayOptions).

Si DisplayOptions carece de vakir doColumnTitles entonces se utilizan los captions por defecto.

Propiedad Strings

Provee acceso al listado de cadenas que alberga los pares Key-Value.
Los pares Key-Value deben encontrarse en el formulario:
'KeyName=Value'

Propiedad ItemProps

Se puede utilizar esta propiedad para controlar como se pueden editar los elementos en las columnas "Value"

Se controla mediante el establecimiento de las propiedades ItemProp's EditStyle y ReadOnly.

Propiedad KeyOptions

KeyOptions es un conjunto de TKeyOptions que controla de que manera el usuario puede modificar los contenidos de la columna "Key".

  • KeyEdit: el usuario puede editar el nombre y la key.
  • KeyAdd: el usuario puede añadir keys (presionando Insert en la grid). KeyAdd requiere KeyEdit.
  • KeyDelete: el usuario puede borrar pares Key-Value (presionando Ctrl+Delete).
  • KeyUnique: si se establece, entonces las Keys deben tener nombres únicos. Un intento de entrar una key duplicada generará una excepción.

Propiedad DropDownRows

Si el editor de celdas es un picklist (ValueEdit1.ItemProps['key1'].EditStyle=esPickList) entonces esta propiedad establece DropDownCount desde el listado mostrado. El valor por defecto es 8.

Función DeleteRow

Borra el par Key-Value de la fila indexada eliminando la fila completamente.

Función InsertRow

Inserta una fila en la grid y establece el par Key-Value. Retorna el índice de la nueva fila insertada.

Función IsEmptyRow

Retorna true si las celdas de la fila insertada están vacias (Keys[aRow]=; Values[aRow]=).

Function FindRow

Retutns the row that has the specified key name.

Funcion RestoreCurrentRow

Deshace la edición en la fila actual (si el editor está todavía enfocado). Sucede cuando el usuario presiona la tecla Escape (Esc).

Comportamiento alterada de algunas propiedades derivado de TCustomStringGrid

Opciones de propiedades

Debido a la naturaleza de TValueListEditor sus opciones tienen ciertas restricciones:

  • goColMoving no está permitida en Options (no puedes establecerla).
  • goAutoAddRows solamente se puede establecer en caso de que KeyAdd se encuentre en KeyOptions. Al establecer KeyAdd automáticamente establecerá goAutoAddRows.
  • goAutoAddRowsSkipContentCheck no está permitida (por tiempo siendo así, causará un crash en TValueListeditor: necesita ser solucionado).
Propiedad FixedRows

Puede valer solamente 1 (mostrar los títulos de las columnas) o 0 (no mostrar los títulos de las columnas).

Propiedad ColCount

Es siempre 2.

Comentarios generales sobre el uso de TValueListEditor

Cuando se manipulan los contenidos de ValueListEditor (la grid), es recomendable manipular las propiedades Strings subyacentes.

Si se necesita insertar o borrar filas, entonces cualquiera de los dos realiza esto accediendo directamente a las Strings, o utilizando los métodos públicos de TValueListEditor: DeleteRow(), InsertRow(), MoveRow() and ExchangeRow().
Si se intenta utiliza métodos ancestros para manipular las filas o las columnas (e.g. Columns.Add) puede desencadenar un crash.

Trabajando con grids

Personalizando grids

Las grid (rejillas) son componentes derivados de la clase TCustomControl, y no tienen un widget nativo asociado, lo cual significa que las grids no se encuentran restringidas por el aspecto del tema que tenga el interface en ese momento. Esto puede suponer tanto una ventaja como una desventaja: habitualmente los programadores necesitan crear un aspecto visual uniforme en las aplicaciones. Las buenas noticias son que las grids de Lazarus son suficientemente flexibles para tomar características de ambos mundo; los programadores pueden crear facilmente grids con aspecto similar a otros controles nativos, o las pueden personalizar al detalle más fino por lo que pueden obtener casi el mismo aspecto en cualquier plataforma o interface widget (esto es, con la excepción de las barras de desplazamiento (scrollbars), porque su aspecto viene todavía determinado por el tema en uso).

Propiedades y Eventos para personalizar las grids

Algunas propiedades pueden afectar la forma en que se visualiza la grid actuando cuando la celda está apunto de ser pintada en PrepareCanvas/OnPrepareCanvas cambiando las propiedades por defecto del canvas (lienzo) tales como brush color o font. Following is a list of such properties:

  • AlternateColor. Con esto el usuario puede cambiar el color de fondo por uno que sirve para alternar de fila en fila de forma que sea más legible el contenido. En el dibujo de debajo el valor de AlternateColor:=clLime; que nos da una alternancia verdosa.


grids alternatecolor.png



  • Color. Establece el color primario para dibujar el fondo de las celdas no fijas. En el dibujo de encima en color blanco Color:=clWhite.
  • FixedColor. Este es el color utilizado para dibujar el fondo de las celdas fijas. En el dibujo de arriba que tiene la primera fila de títulos fija y la primera columna también fija FixedColor:=clSkyBlue; les da un color azulado.
  • Flat. Con Flat:=True; la grid tiene un aspecto plano con Flat:=False presenta un aspecto 3D más estilizado como en el dibujo de arriba.
  • TitleFont. Establece que fuente se utiliza para dibujar el texto de las celdas fijas de la fila de título.
  • TitleStyle. This property changes the 3D look of fixed cells, there are 3 settings:
    • tsLazarus. Este es el aspecto por defecto.
    • tsNative. Trata de establecer un aspecto conforme al tema actual del widgetset.
    • tsStandard. Este estilo le da un aspecto más contrastado, similar al de las grids de Delphi.
grids titlestyle.png
  • AltColorStartNormal. Booleano. Si vale 'True: el color de alternancia aparece siempre en la segunda fila después de las filas fijas, , la primera fila después de las filas fijas será siempre el correspondiente al valor de color. Si vale False, entonces el color por defecto se establece a la primera fila, como si no hubiese filas fijas.
  • BorderColor. This sets the grid's border color used when Flat:=True and BorderStyle:=bsSingle;
  • EditorBorderStyle. If set to bsNone bajo Windows los editores de celda no tendrán el borde, como en Delphi, establecer a bsSingle por defecto porque el borde puede ser específico de un tema en algunos widgetsets y para permitir un aspecto uniforme.
  • FocusColor. El color a utilizar para dibujar la celda actualmente enfocada si UseXORFeatures no está establecida, por defecto FocusColor:=clRed.
  • FocusRectVisible. Turns on/off the drawing of focused cell.
  • GridLineColor. Color of grid lines in non fixed area.
  • GridLineStyle. Pen style used to draw lines in non fixed area, possible choices are: psSolid, psDash, psDot, psDashDot, psDashDotDot, psinsideFrame, psPattern,psClear. default is psSolid.
  • SelectedColor. Color used to draw cell background on selected cells.
  • UseXORFeatures. If set, focus rect is drawn using XOR mode so it should make visible the focus rect in combination with any cell color ackground. It also affects the moving columns look.
  • DefaultDrawing. Boolean. Normally the grids prepare the grid canvas using some properties according to the kind of cell that is being painted. If the user writes an OnDrawCell event handler, a set DefaultDrawing also paints the cell background. If the user draws the cell himself, it is better to turn off this property so painting is not duplicated. In a StringGrid, a set DefaultDrawing dibuja el texto en cada celda.
  • AutoAdvance. donde irá el cursor de celdas cuando se presione enter, o después de una edición.
  • TabAdvance. donde irá el cursor de celdas cuando se presione Tab o Shift-Tab.
  • ExtendedColSizing. Si vale true entonces el usuario puede redimensionar las columnas no solamente en la cabecera sino a lo largo de toda la altura de la columna.

Otras propiedades que también afectan al aspecto de las grids.

Options.

La propiedad Options' es un conjunto con algunos elementos para habilitar diversas funcionalidades pero algunas están relacionadas directamente con el aspecto de la grid. Estas opciones pueden establecerse tanto en tiempo de diseño como durante la ejecución del programa.
  • goFixedVertLine, goFixedHorzLine dibuja respectivamente una línea vertical u horizontal delimitan celdas o columnas en un área fija, activa por defecto.
  • goVertLine, goHorzLine lo mismo que la anterior, pero con un área normal visible. Se puede construir una grid que simule un listbox desestablecidendo estos dos elementos.
  • goDrawFocusSelected si se habilita este elemento entonces se pinta una selección de fondo en la celda con foco en adición al rectangulo punteado con foco (ten en cuenta que esto no funciona todavía cuando la opción goRowSelect está establecida, en tal caso la fila siempre se pinta como si goDrawFocusSelected estuviese establecida).
  • goRowSelect selecciona la fila completa en lugar de celdas individuales.
  • goFixedRowNumbering si se establece, la grid realizará un numerado en su primera columna fija.
  • goHeaderHotTracking si se establece, la grid tratará de mostrar un aspecto diferente cuando el cursor del ratón entre en el área de cualquier celda fija. Para que esto funcione, la zona de celda deseada necedita tener habilitada su propiedad HeaderHotZones. Prueba a combinar esta opción con la propiedad TitleStyle:=tsNative para obtener un aspecto themed hot tracking.
  • goHeaderPushedLook si se establece, este elemento habilita un aspecto de pulsado cuando se hace click en una celda fija. La zona de celda "pulsable" se habilita utilizando la propiedad HeaderPusedZones.

(escribir más contenido) <<>>

property OnBeforeSelection: TOnSelectEvent

property OnCompareCells: TOnCompareCells

property OnPrepareCanvas: TOnPrepareCanvasEvent

property OnDrawCell: TOnDrawCell

property OnEditButtonClick: TNotifyEvent

property OnSelection: TOnSelectEvent

property OnSelectEditor: TSelectEditorEvent

property OnTopLeftChanged: TNotifyEvent

procedure AutoAdjustColumns;

procedure BeginUpdate;

procedure Clear;

procedure DeleteColRow(IsColumn: Boolean; index: Integer);

function EditorByStyle(Style: TColumnButtonStyle): TWinControl;

procedure EndUpdate(UO: TUpdateOption); overload;

procedure EndUpdate(FullUpdate: Boolean); overload;

procedure EndUpdate; overload;

procedure ExchangeColRow(IsColumn: Boolean; index, WithIndex:Integer);

function IscellSelected(aCol,aRow: Integer): Boolean;

function IscellVisible(aCol, aRow: Integer): Boolean;

procedure LoadFromFile(FileName: string);

function MouseToCell(Mouse: TPoint): TPoint; overload;

function MouseToLogcell(Mouse: TPoint): TPoint;

function MouseToGridZone(X,Y: Integer): TGridZone;

function CellToGridZone(aCol,aRow: Integer): TGridZone;

procedure MoveColRow(IsColumn: Boolean; FromIndex, ToIndex: Integer);

procedure SaveToFile(FileName: string);

procedure SortColRow(IsColumn: Boolean; index:Integer); overload;

procedure SortColRow(IsColumn: Boolean; index,FromIndex,ToIndex: Integer); overload;

property AllowOutboundEvents:boolean;

Protegida en TCustomGrid, pública (public) en TCustomDrawGrid y descendientes. Normalmente cuando un usuario hace click en un punto sobre un espacio vacío después de las celdas (por ejemplo si la grid tiene tres filas pero el usuario hace click en una imaginaria cuarta fila) la celda seleccionada (que obtiene el foco:focused) se moverá a la celda más cercana al punto que se ha realizado el click, podemos llamar a esto un evento externo y su valor por defecto es verdadero (true) y es un comportamiento que se añadió desde un principio. Esta propiedad fue añadida para simular el comportamiento que tienen en Delphi donde los eventos fuera de su área de acción no estan disponibles. Si se desea mantener la compatibilidad con Delphi se debe establecer esta propiedad al valor falso (false).

TCustomStringGrid

TCustomStringGrid sirve como la base para TStringGrid. Se puede utilizar para componentes derivados de TStringGrid que necesiten ocultar las propiedades publicass. Ver new intermediate grids para mas informacion.

Las siguinetes propiedades o metodos son publicos y estan tambien disponibles para TStringGrid.

See the full TCustomStringGrid Reference

procedure AutoSizeColumn(aCol: Integer);

This procedure sets the column width to the size of the widest text it finds in all rows for the column aCol. Tip: see the goDblClickAutoSize option to allow columns to be automatically resized when doubleClicking the column border.

procedure AutoSizeColumns;

Automáticamente redimensiona todas las columnas ajustándolas en ancho para caber la cadena de texto más larga en cada columna. Este es un método rápido de aplicar AutoSizeColumn() para todas las columnas en la rejilla.

procedure Clean; overload;

Limpia todas las celdas en el grid, tanto las fijas como las normales.

procedure Clean(CleanOptions: TGridZoneSet); overload;

Cleans all cells in the grid subject to the given CleanOptions. See TGridZoneSet for more information. Some examples:

  • Clean all cells: grid.Clean([]); (the same as grid.clean)
  • Clean all non fixed cells: grid.Clean([gzNormal]);
  • Clean all cells but don't touch grid column headers: Grid.Clean([gzNormal, gzFixedRows]);

procedure Clean(StartCol,StartRow,EndCol,EndRow: integer; CleanOptions:TGridZoneSet); overload;

Hace lo mismo que Clean(CleanOptions:TGridZoneSet) pero restringido a StartCol,StartRow,EndCol y EndRow. Ejemplos:

  • Clean column index 4 a 6 pero no toca las cabeceras (headers) de las columnas del grid: algunas variaciones, Grid.Clean(4,Grid.FixedRows,6,Grid.RowCount-1,[]); Grid.Clean(4,0,6,Grid,RowCount-1, [gzNormal]); etc.

procedure Clean(aRect: TRect; CleanOptions: TGridZoneSet); overload;

The same as Clean(StartCol,StartRow,EndCol,EndRow, CleanOptions), just taking a TRect instead of individual cell coordinates. Useful to clean the selection: grid.Clean(Grid.Selection,[]);

property Cols[index: Integer]: TStrings read GetCols write SetCols;

Get/set a list of strings from/to the given grid's column index starting from row index 0 to RowCount-1.

Examples
  • Set Example: Set the content of the third column in the grid from a ListBox:
Grid.Cols[2] := ListBox1.Items;
  • Get Example: Set the content of a Listbox from the grid's column index 4:
procedure TForm1.FillListBox1;
var 
  StrTempList: TStringList;
begin
  StrTempList := TStringList(Grid.Cols[4]);
  if StrTempList<>nil then begin
    ListBox1.Items.Assign(StrTempList);
    StrTempList.Free;
  end;
end;   
Notes.

Esta propiedad funciona de manera diferente en Lazarus con respecto a Delphi cuando se obtienen los datos de la grid. En Lazarus se crea un objeto temporal tipo TStringList para recabar el contenido de la columna. Es responsabilidad del usuario liberar este objeto despues de usarlo.

Esto significa ademas que los cambios en la lista obtenida no afectaran al contenido de la grid or layout.

See the Get Example.

property Rows[index: Integer]: TStrings read GetRows write SetRows;

Obtiene/establece (get/set) un listado de cadenas (strings) del indice de filas del grid utilizado desde el índice de columna 0 hasta cuenta final de columna-1.

Notas.

Esta propiedad funciona de una manera diferente a su equivalente en Delphi a la hora de obtener los datos de la grid. En Lazarus se crea un objeto TStringList temporal para obtener el contenido de la fila. Precisa que el programador controle que se libere este objeto después de usarlo. Esto significa además que los cambios en el listado obtenido no afectarán al contenido de la grid o diseño.

Ejemplos
  • Ejemplo Set: Establecer el contenido de la tercera fila en la grid desde un ListBox:
Grid.Rows[2] := ListBox1.Items;
  • Ejemplo Get: Establecer el contenido de una Listbox desde la fila con índice 4 de la grid (rejilla).
 procedure TForm1.FillListBox1;
 var 
   StrTempList: TStringList;
 begin
   StrTempList := TStringList(Grid.Rows[4]);
   if StrTempList<>nil then begin
     ListBox1.Items.Assign(StrTempList);
     StrTempList.Free;
   end;
 end;  
*Un ejemplo que no funciona, y su solución: el listado de cadenas obtenido es de solo lectura
 // esto no funcionará y causará un leak de memoria
 // porque el StringList obtenido no se liberará.
 Grid.Rows[1].CommaText := '1,2,3,4,5';
 Grid.Rows[2].Text := 'a'+#13#10+'s'+#13#10+'d'+#13#10+'f'+#13#10+'g'; 
 
 // solucionando el primer caso
 Lst:=TStringList.Create;
 Lst.CommaText := '1,2,3,4,5';
 Grid.Rows[1] := Lst;
 Lst.Free; 
// Tal como se indicaba más arriba es tarea del programador 
// liberar el objeto anteriormente creado.

property UseXORFeatures;

Propiedad booleana, valor por defecto: False;

Esta propiedad controla como aparece en la grid el rectangulo punteado que tiene el focus (que está seleccionado). Cuando tiene el valor True el rectángulo se dibuja realizando un XOR sobre el objeto que dibuja. Esto permite observar el rectángulo en la celda que esta seleccinada (focus) sin importar el color de fondo que tenga. Cuando tiene el valor False entonces el programador puede controlar el color del rectángulo de selección utilizando la [Propiedad Focus [FocusColor property ]] También controla el aspecto del redimensionado columna/fila. Cuando su valor es True, una línea visualiza el tamaño que tendrá la fila o la columna justo como la deje en ese momento el programador. Cuando su valor sea False, la redimensión de la fila o la columna tendrá efecto cuando el usuario deje de arrastrar el cursor del ratón.

Grids Howto

Customizing grids

Las grid son componentes derivados de la clase TCustomControl y no tienen un widget nativo asociado, lo cual significa que no están restringidas al aspecto que tenga en ese momento el tema del interface. Esto puede ser al mismo tiempo tanto una ventaja como una desventaja: habitualmente los programadores necesitan crear una aplicación con aspecto uniforme. Las buenas noticias son que las grids de Lazarus son suficientemente flexibles para tener cosas de ambos mundos; los programadores pueden creaer grids con un aspecto similar a otros controles nativos, o pueden personalizar la grid hasta el más mínimo detalle lo que permite obtener practicamente el mismo aspecto en cualquier plataforma o interface widget (exceptuando, claro está, los scrollbars, porque su aspecto todavía queda determinado por el tema actual en uso).

Propiedades y Eventos para personalizar grids

Algunas propiedades pueden modificar la forma en que se visualiza el rejilla actuando cuando la celda se va a dibujar en PrepareCanvas/OnPrepareCanvas mediante la modificación de propiedades por defecto tipo canvas tales como brush color (color de brocha) o font (fuente). El siguiente es un listado de dichas propiedades:

  • AlternateColor. With this the user can change the background color appears on alternated rows. This is to allow easy reading off of grid rows data.
  • Color. Establece el color primario a utilizar para dibujar celdas de fondo no fijas.
  • FixedColor. Es el color a utilizar para dibujar el color de fondo de celdas.

Flat. Elimina el aspecto 3D de las celdas.

  • TitleFont. Fuente utilizada para dibujar las celdas.
  • TitleStyle. Esta propiedad cambia el aspecto 3D de las celdas, tiene 3 posibles variantes:
    • tsLazarus. Este es el aspecto predeterminado.
    • tsNative. Este trata de establecer una aspceto que está en concordancia con el tema actual del widgetset.
    • tsStandard. Este estilo es el más contrastado, similar a las grids de Delphi.
  • AltColorStartNormal. boolean, if true alternate color is always in the second row after fixed rows, the first row after fixed rows will be always color, if false default color is set to the first row as if there were no fixed rows.
  • BorderColor. This sets the grid's border color used when Flat:=True and BorderStyle:=bsSingle;
  • EditorBorderStyle. If set to bsNone under windows the cell editors will not have the border, like in delphi, set to bsSingle by default because the border can be theme specific in some widgetsets and to allow a uniform look.
  • FocusColor. The color used to draw the current focused cell if UseXORFeatures is not set, by default this is clRed.
  • FocusRectVisible. turns on/off the drawing of focused cell.
  • GridLineColor. color of grid lines in non fixed area.
  • GridLineStyle. Pen style used to draw lines in non fixed area, possible choices are: psSolid, psDash, psDot, psDashDot, psDashDotDot, psinsideFrame, psPattern,psClear. default is psSolid.
  • SelectedColor. Color used to draw cell background on selected cells.
  • UseXORFeatures. If set, focus rect is drawn using XOR mode so it should make visible the focus rect in combination with any cell color ackground. It also affects the moving columns look.
  • DefaultDrawing. boolean. Normally the grids prepare the grid canvas using some properties according to the kind of cell is being painted. If user write an OnDrawCell event handler, DefaultDrawing if set also paints the cell background, if user is drawing fully the cell is better turn off this property so painting is not duplicated. In a StringGrid if DefaultDrawing is set it draws the text in each cell.
  • AutoAdvance. where the cell cursor will go when pressing enter or tab/shift tab, or after editing.
  • ExtendedColSizing. If true user can resize columns not just at the headers but along the columns height.

Other properties that also affect the grids look.

Options. Options property is a set with some elements to enable diverse functionality but some are related directly with grid's look. Estas opciones se pueden establecer tanto durante su diseño como durante la ejecución del programa.

  • goFixedVertLine, goFixedHorzLine Dibuja una línea horizontal o vertical respectivamente, delimitando celdas o columnas en un área fija, activo por defecto.
  • goVertLine, goHorzLine the same as previous, but for normal browseable area. A grid can be made to simulate a listbox by unsetting both of this elements.
  • goDrawFocusSelected if this element is enabled a selection background is painted in focused cell in addition to focused dotted rectangle (note this doesn't work yet when goRowSelect option is set, in such case row is always painted as if goDrawFocusSelected is set)
  • goRowSelect Selecciona la fila completa en lugar de únicamente celdas indivicuales.
  • goFixedRowNumbering if set, grid will do numbering of rows in first fixed column
  • goHeaderHotTracking if set, the grid will try to show a different look when the mouse cursor is overing any fixed cell. In order for this to work, desired cell zone needs to be enabled with property HeaderHotZones. Try combining this option with property TitleStyle:=tsNative to get themed hot tracking look.
  • goHeaderPushedLook if set, this element enables a pushed look when clicking any fixed cell. The zone of "pushable" cells is enabled using HeaderPusedZones property.

(escribir más)

Description of grid's drawing process

Like other custom controls, the grid is drawn using the paint method. In general terms the grid is drawn by painting all rows, and each row by painting its individual cells.

The process is as follow:

  • First the visible cells area is determined: each row is tested to see if it intersects the canvas clipping region; if it's ok, then the visible area is painted by drawing columns of each row.
  • The column and row values are used to identify the cell that is about to be painted and again each column is tested for intersection with the clippling region; if everything is ok, some additional properties like the cell's rectangular extent and visual state are passed as arguments to the DrawCell method.
  • As the drawing process is running, the visual state of each cell is adjusted according to grid options and position within grid. The visual state is retained in a varible of type TGridDrawState which is a set with following elements:
    • gdSelected The cell will have a selected look.
    • gdFocused The cell will have a focused look.
    • gdFixed Cell have to be painted with fixed cell look.
    • gdHot the mouse is over this cell, so paint it with hot tracking look
    • gdPushed the cell is being clicked, paint it with pushed look
  • DrawCell. The DrawCell method is virtual and may be overriden in descendant grids to do custom drawing. The information passed to DrawCell helps to identify the particular cell is being painted, the physical area ocuppied in screen and its visible status. See DrawCell reference for details. For each cell the following occurs:
  • PrepareCanvas. In this method, if the DefaultDrawing property is set, the grid canvas is setup with default properties for brush and font based on current visual state. For several design and runtime properties, the text alignment is set to match programmer selection in custom columns if they exists. If DefaultDrawing is false, brush color is set to clWindow and Font color to clWindowText, the text alignment is set with grids defaultTextStyle property value.
  • OnPrepareCanvas. If the programmer wrote an event handler for OnPrepareCanvas event, it is called at this point. This event can be used for doing simple customization like changing cell's background color, font's properties like color, fontface and style, Text layout like different combinations of left, center, top, bottom, right alignment, etc. Any change made to the canvas in this event would be lost, because the next cell drawing will reset canvas again to a default state. So it's safe doing changes only for particular cell or cells and forget about it for the rest. Using this event sometimes helps to avoid using the OnDrawCell grid event, where users would be forced to duplicate the grid's drawing code. Todo: samples of what can be made and what to leave for OnDrawCell?...
  • OnDrawCell. Next if no handler for OnDrawCell event was specified, the grid calls the DefaultDrawCell method which simply paints the cell background using the current canvas brush color and style. If the OnDrawCell handler exists, the grid first paints the cell background but only if DefaultDrawing property was set, then it calls OnDrawCell event to do custom cell painting. Usually programmers want to do custom drawing only for particular cells, but standard drawing for others; in this case, they can restrict custom operation to certain cell or cells by looking into ACol, ARow and AState arguments, and for other cells simply call DefaultDrawCell method and let the grid to take care of it.
  • Text. At this point (only for TStringGrid) if DefaultDrawing property is true, the cell's text content is painted.
  • Grid lines. The last step for each cell is to paint the grid lines: if grid options goVertLine, goHorzLine, goFixedVertLine and goFixedHorzLine are specified the cell grid is drawn at this point. Grids with only rows or only cols can be obtained by changing these options. If the programmer elected to have a "themed" look it is done at this point also (see property TitleStyle).
  • FocusRect. When all columns of current row have been painted it is time to draw the focus rectangle for the current selected cell or for the whole row if goRowSelect option is set.

Grid's cell selection

The location of a grid's current (focused) cell (or row) can be changed using keyboard, mouse or through code. In order to change cell focus successfully to another position, we must test the target position to see if it is allowed to receive cell focus. When using keyboard, the property AutoAdvance performs part of the process by finding what should be the next focused cell. When using mouse clicks or moving by code, focus will not move from the current cell unless the target cell is permitted to receive focus.

The grid calls function SelectCell to see if a cell is focusable: if this function returns true, then the target cell identified with arguments aCol and aRow is focusable (the current implementation of TCustomGrid simply returns true). TCustomDrawGrid and hence TDrawGrid and TStringGrid override this method to check first if cell is any wider than 0; normally you don't want a 0 width cell selected so a cell with this characteristics is skipped automatically in the process of finding a suitable cell. The other thing the overriden method SelectCell does is to call the user configurable event OnSelectCell: this event receives the cell coordinates as arguments and always returns a default result value of true.

Once a cell is known to be focusable and we are sure a movement will take place, first the method BeforeMoveSelection is called; this in turns triggers the OnBeforeSelection event. This method's arguments are the coordinates for the new focused cell, at this point any visible editor is hidden too. The "before" word means that selection is not yet changed and current focused coordinates can be accessed with grid.Col and grid.Row properties.

After that, the internal focused cell coordinates are changed and then method MoveSelection is called; this method's purpose is to trigger the OnSelection event if set (this is a notification that the focused cell has, by this time, already changed and cell coordinates are now available through grid.row and grid.col properties).

Note that is not good to use OnSelectCell event to detect cell focus changes, as this event will be triggered several times even for the same cell in the process of finding a suitable cell. Is better to use OnBeforeSelection or OnSelection events for this purpose.

Several differences with Delphi have been identified

  • In Lazarus TCustomGrid.DrawCell method is not abstract and its default implementation does basic cell background filling.
  • In Delphi, the cell's text is drawn before entering the OnDrawCell event (see bug report #9619).
  • SelectCell and OnSelectCell behaviour is probably different - can't really comment on the differences. In Lazarus they are used in functionality like AutoAdvance which as far as I know doesn't exist in Delphi.

When above customizaton is not enough, derived grids

Derived grids usually have to override following methods:
DrawAllRows: Draws all visible rows.
DrawRow: Draw All Cells in a Row.
DrawRow draws all cells in the row by first checking if cell is within clipping region, and only draws the cell if it is.
DrawCell:
DrawCellGrid:
DrawCellText:
DrawFocusRect:
(write me).

Operations

Focusing a cell

Focusing a cell in TStringGrid is easy. Note that counting starts from zero not 1. So to focus row 10, column 9, do:

StringGrid1.row := 9;
StringGrid1.col := 8;

Save and Retrieve Grid Content

The SaveToFile procedure allows you save the TStringGrid format, attributes & values to a XML file. Previously you must set the SaveOptios property as follow:

soDesign:     Save & Load ColCount,RowCount,FixedCols,FixedRows,
              ColWidths, RowHeights and Options (TCustomGrid)
soPosition:   Save & Load Scroll Position, Row, Col and Selection (TCustomGrid)
soAttributes: Save & Load Colors, Text Alignment & Layout, etc. (TCustomDrawGrid)
soContent:    Save & Load Text (TCustomStringGrid)

The LoadFromFile procedure allows you to load into a StringGrid instance, attributes, formats & values, from a XML file. First, you must set some of this options of the SaveOptions property (on your TStringGrid instance) SaveOptions

 soDesign:     Save & Load ColCount,RowCount,FixedCols,FixedRows,
               ColWidths, RowHeights and Options (TCustomGrid)
 soPosition:   Save & Load Scroll Position, Row, Col and Selection (TCustomGrid)
 soAttributes: Save & Load Colors, Text Alignment & Layout, etc. (TCustomDrawGrid)
 soContent:    Save & Load Text (TCustomStringGrid)

Example:

  1. First, go to menu "File -> New -> Application";
  2. Put an empty TStringGrid;
  3. Put a TButton and TOpenDialog;
  4. Add the event OnCreate for the Form;
  5. Add the event OnClick for the Button.
unit Unit1; 

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, Grids,
  Buttons, StdCtrls, XMLCfg;

type

  { TForm1 }
  TForm1 = class(TForm)
    StringGrid1: TStringGrid;
    Button1: TButton;
    OpenDialog1: TOpenDialog;
    procedure Button1Click(Sender: TObject);
    procedure Form1Create(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end; 

var
  Form1: TForm1; 

implementation

{ TForm1 }

procedure TForm1.Form1Create(Sender: TObject);
begin
 //sets the SaveOptions at creation time of the form 
 stringgrid1.SaveOptions := [soDesign,soPosition,soAttributes,soContent];
end;


procedure TForm1.Button1Click(Sender: TObject);
begin
 //Ask if thew Execute method of the OpenDialog was launched 
 //when this occurs, the user selects an XML file to Load
 //wich name was stored in the FileName prop.

 if opendialog1.Execute then
 Begin
   //Clear the grid 
   StringGrid1.Clear;
   //Load the XML
   StringGrid1.LoadFromFile(OpenDialog1.FileName);
   //Refresh the Grid
   StringGrid1.Refresh;
 End;
end;

initialization
  {$I unit1.lrs}

end.

The sample xml file: (Copy the text below into a txt file. Don't forget put the xml header :-))

<?xml version="1.0"?>
<CONFIG>
  <grid version="3">
    <saveoptions create="True" position="True" content="True"/>
    <design columncount="2" rowcount="5" fixedcols="1" fixedrows="1" defaultcolwidth="64" defaultRowHeight="20">
      <options>
        <goFixedVertLine value="True"/>
        <goFixedHorzLine value="True"/>
        <goVertLine value="True"/>
        <goHorzLine value="True"/>
        <goRangeSelect value="True"/>
        <goDrawFocusSelected value="False"/>
        <goRowSizing value="False"/>
        <goColSizing value="False"/>
        <goRowMoving value="False"/>
        <goColMoving value="False"/>
        <goEditing value="False"/>
        <goTabs value="False"/>
        <goRowSelect value="False"/>
        <goAlwaysShowEditor value="False"/>
        <goThumbTracking value="False"/>
        <goColSpanning value="False"/>
        <goRelaxedRowSelect value="False"/>
        <goDblClickAutoSize value="False"/>
        <goSmoothScroll value="True"/>
      </options>
    </design>
    <position topleftcol="1" topleftrow="1" col="1" row="1">
      <selection left="1" top="1" right="1" bottom="1"/>
    </position>
    <content>
      <cells cellcount="10">
        <cell1 column="0" row="0" text="Title Col1"/>
        <cell2 column="0" row="1" text="value(1.1)"/>
        <cell3 column="0" row="2" text="value(2.1)"/>
        <cell4 column="0" row="3" text="value(3.1)"/>
        <cell5 column="0" row="4" text="value(4.1)"/>
        <cell6 column="1" row="0" text="Title Col2"/>
        <cell7 column="1" row="1" text="value(1.2)"/>
        <cell8 column="1" row="2" text="value(2.2)"/>
        <cell9 column="1" row="3" text="value(3.2)"/>
        <cell10 column="1" row="4" text="value(4.2)"/>
      </cells>
    </content>
  </grid>
</CONFIG>

--Raditz 21:06, 11 Jan 2006 (CET) from ARGENTINA

Grid Cell Editors

El grid utiliza el editor de celdas para cambiar el contenido de las mismas.

Para una grid especializada como puede ser TStringGrid, el editor es el usual control de edición de línea simple, pero en otras ocasiones es preferible tener otros medio de entrar la información. Por ejemplo, para llamar al diálogo de apertura de fichero para encontrar la localización de un fichero de manera que el usuario no tenga que escribir manualmente la trayectoria; si el texto en la celda representa una fecha, sería más amigable si se pudiese mostrar un calendario de forma que se pudiese escoger una fecha fácilmente.

Algunas veces la información que debe introducir el usuario en la celda se restringe a un listado limitado de palabras; en este caso escribir la información directamente puede inducir a errores y requerir rutinas de validación en su implementación. Se puede evitar esto utilizando un editor de celdas que presente al usuario este listado con las palabras en su valor correcto.

Este es también el caso para grids genéricas, como TDrawGrid, donde los usuarios necesitan algún tipo de estructura para mantener los datos que se mostrarán en la grid. En este caso la información introducida en el editor de celda actualiza la estructura interna para reflejar los cambios en la grid.

Builtin cell editors

The grids.pas unit already includes some of the most used cell editors ready for use in grids. It is also possible to create new cell editors (custom cell editors) if the built-in editors are not appropiate for a specific task.

The builtin cell editors are Button, Edit, and Picklist.

Utilizando editores de celdas

Los usuarios pueden especificar el editor a usar escogiendo entre dos métodos disponibles.

  1. Using a custom column and selecting the ButtonStyle property of the column. In this method the user can select the style of the editor that will be shown. Available values are: cbsAuto, cbsEllipsis, cbsNone, cbsPickList, cbsCheckboxColumn.
  2. Using OnSelectEditor grid event. Here the user specifies in the Editor parameter which editor to use for a cell identified for column aCol and row ARow in a TCustomDrawGrid derived grid or TColumn in TCustomDBGrid. For this purpose there is a useful public function of grids, EditorByStyle() that takes as parameter one of the following values: cbsAuto, cbsEllipsis, cbsNone, cbsPickList, cbsCheckboxColumn. This method takes precedence over the first one using custom columns. A Custom cell editor can be specified here. This event is also the place to setup the editor with values specific to the cell, row or column.

Description of editor styles

La siguiente es una descripción de los estilos del editor. Son valores enumerados del tipo TColumnButtonStyle and so they are prefixed by 'cbs'. Este tipo se utiliza para mantener la compatibilidad con DBGrid de Delphi.

  • cbsAuto
This is the default editor style for TCustomGrid derived grids. The actual editor class that will be used to edit the cell content depends on several factors. For TCustomGrids it uses a TStringCellEditor class derived from TCustomMaskEdit. This editor is specialized to edit single line strings. It is then used in TStringGrid and TDrawGrid by default. When using Custom Columns, if the programmer filled the Column's PickList property, this behaves as if cbsPickList editor style was set. For a TCustomDBGrid that has a field of type boolean, it behaves as if cbsCheckBoxColumn editor style was specified. This is the recommended value for Custom Cell Editors. TODO: related OnEditingDone.
  • cbsEllipsis
This editor style is the most generic one. When used, a button appears in the editing cell and programmers could use the OnEditButtonClick grid event to detect when the user has pressed the button and take any action programmed for such a cell. For example a programmer could use this editor style to pop up a calendar dialog to allow the user easily to select a specific date. Other possibilities could be to show a file open dialog to find files, a calculator so user can enter the numeric result of calcs, etc.
OnEditButtonClick is just a notification, to find out in which cell a button has been clicked by taking a look at the grid.Row and grid.Col properties.
A DBGrid has specific properties to retrieve the active column or field and because this event occurs in the active record, it could update the information in the active field.
This editor style is implemented using TButtonCellEditor, a direct descendant of TButton.
  • cbsNone
This editor style instructs the grid not to use any editor for a specific cell or column; it behaves then, as if the grid were readonly for such a cell or column.
  • cbsPickList
Used to present the user with a list of values that can be entered. This editor style is implemented using TPickListCellEditor, a component derived from TCustomComboBox. The list of values that are shown is filled in one of two ways depending on the method used to select the editor style.
  1. When using custom columns, programmers can enter a list of values using the column's PickList property. [FOR BEGINNERS: TODO: exact procedure to edit the list]
  2. In OnSelectEditor, programmers get the TPickListCellEditor instance using the function EditorByStyle(cbsPickList). An example would be:
var Lst:TPickListCellEditor; 
  begin [...] 
    Lst:=TPickListCellEditor(EditorByStyle(cbsPickList)); 
    Lst.clear; 
    Lst.Items.add('One'); 
    Lst.items.add('Two'); 
    Editor:=Lst; 
  end;
The value in a TStringGrid grid will automatically reflect the value selected. If necessary the programmer could detect the moment the value is selected by writing an event handler for the grid's OnPickListSelect event, so additional steps can be taken (for example, to process the new value). TODO: related OnEditingDone.
  • cbsCheckboxColumn
This editor style is at the moment only available in TDBGrid. It can be useful when field contents associated with the column are restricted to a pair of values, for example, yes-no, true-false, on-off, 1-0, etc. Instead of forcing the user to type the values for this kind of field in a StringCellEditor or to choose one from a list, cbsCheckboxColumn is used to modify the field content of a column by using a checkbox representation that the user can toggle by using a mouse click or pressing the SPACE key.
If a columns' ButtonStyle property is set to cbsAuto and DBGrid detects that the field associated with the column is a boolean field, then the grid uses this editor style automatically. This automatic selection can be disabled or enabled using DBGrid's OptionsExtra property; setting dgeCheckboxColumn element to false disables this feature.
The values that are used to recognize the checked or unchecked states are set in a column's properties ValueChecked and ValueUnchecked.
At any moment, the field value can be in one to three states: Unchecked, Checked or Grayed. Internally these states are identified by the following values of type TDBGridCheckBoxState: gcbpUnChecked, gcbpChecked and gcbpGrayed.
This editor style doesn't use real TCheckbox components to handle user interaction: the visual representation is given by three builtin bitmap images that corresponds to the possible states of checkbox. The used bitmaps can be customized by writing a handler for DBGrid event OnUserCheckboxBitmap; the handler of this event gets the state of the checkbox in the parameter CheckedState of type TDBGridCheckboxState and a bitmap parameter that the programmer could use to specify custom bitmaps.

Example: How to set a custom cell editor

See lazarus/examples/gridcelleditor/gridcelleditor.lpi

Todo

  • TInplaceEditor Support

known problems

29-marzo-2005:

  • mouse autoedit
    • linux: clicking a selected cell doesn't trigger the autoedit function (the editor lost focus inmmediatelly)
    • windows: it should work only if the grid has the focus, if not it should focus and a second click should autoedit (cannot detect if the grid was previously focused or not)
  • ColumnWidths: linux, windows: dbgrid start with default column widths instead of calculated ones (it's disabled because early canvas creation causes strange effects if the parent is a notebook page)
  • Resizing Columns: linux, windows. Resizing a column should not hide the editor (specially in dbgrid if we are inserting)
  • MouseWheel:
    • linux: mousewheel doesn't work as it should, (seems it's calling the default mousewheel handler)
    • windows: patch was sent.
  • Double painting: Apparently dbgrid paints the cell background twice (once with fillrect and once in textRect)
  • AutoFillColumns: sometimes the clientwidth is evaluated incorrectly (sometimes there are phantom scrollbars)