Difference between revisions of "FPSpreadsheet tutorial: Writing a mini spreadsheet application/es"

From Free Pascal wiki
Jump to navigationJump to search
Line 110: Line 110:
 
Puede que se necesite cambiar <code>TitleStyle</code> a <code>tsNative</code> en la grid para lograr el themed painting de la cabecera de la fila y columna. Y aquí también es un buen lugar para adaptar las <code>Options</code> de la grid para activar algunas características bien conocidas de las hojas de cálculo:
 
Puede que se necesite cambiar <code>TitleStyle</code> a <code>tsNative</code> en la grid para lograr el themed painting de la cabecera de la fila y columna. Y aquí también es un buen lugar para adaptar las <code>Options</code> de la grid para activar algunas características bien conocidas de las hojas de cálculo:
  
* <code>goEditing</code> must be active, otherwise the grid contents cannot be modified.  
+
* <code>goEditing</code> debe estar activo, de otra manera el contenido de la grid no se podrá modificar.  
* <code>goAlwaysShowEditor</code> should be off because it interferes with the editing convention of spreadsheet applications.
+
* <code>goAlwaysShowEditor</code> debe estar off porque interfiere with the editing convention de las aplicaciones de hojas de cálculo.
* <code>goColSizing</code> enables changing of the column width by dragging the dividing line between adjacent column headers. Dragging occurs with the left mouse button pressed.
+
* <code>goColSizing</code> habilita cambiar el ancho de columna a través del dragging de la línea divisoria que encontramos en las cabeceras de las columnas adyacentes.. Dragging tiene lugar con el pulsador izquierdo del ratón presionado.
* <code>goRowSizing</code> does the same with the row heights.
+
* <code>goRowSizing</code> realiza lo mismo con la altura de las filas.
* <code>goDblAutoResize</code> activates the feature that optimum column width can be set by double-clicking in the header on its dividing line to the next column. The "optimum" column width is such that no cell content is truncated and no extra space is shown in the column.
+
* <code>goDblAutoResize</code> activa la característica de optimización de ancho de columna que se obtiene haciendo doble click en la línea divisoria del encabezado de la columna que se situa hacia al siguente columna. La "optimum" ancho de columna es tal que no se trunca el contenido de la celda y no se muestra espacio extra sobrante.
* <code>goHeaderHotTack</code> gives visual feedback if the mouse is above a header cell.
+
* <code>goHeaderHotTack</code> nos da información adicional si se pasa el cursor del ratón por encima de la cabecera de las celdas.
* <code>goRangeSelect</code> (which is on by default) enables selection of a rectangular range of cells by dragging the mouse between cells at opposite corners of the rectangle. If you have Lazarus trunk you can even select multiple rectangles by holding the CTRL key down before the next rectangle is dragged - in the release version of Lazarus (1.2.6 at the time of this writing) only a single range can be selected.
+
* <code>goRangeSelect</code> (se encuentra "on" por defecto) y habilita la selección de un rango rectangular de celdas haciendo click con el pulsador izquierdo del ratón y sin soltarlo arrastrandolo hasta completar la selección de celdas (en definitiva de esquina a esquina opuesta del rectángulo). Si se tiene una versión de Lazarus del trunk y incluso se puede realizar una selección multiple de areas rectangulares manteniendo pulsada la tecla CTRL antes de seleccionar el siguente rectángulo - en la versión 1.2.6 de Lazarus (en el momento de estribir esto) solamente se permite la selección de un rango.
* <code>goThumbTracking</code> activates immediate scrolling of the worksheet if one of the scrollbars is dragged with the mouse. The Office applications usually scroll by lines; you can achieve this by turning off <code>goSmoothScroll</code>.
+
* <code>goThumbTracking</code> activa el scrolling inmediato de la hoja (Worksheet) si una de las barras de desplazamiento es arrastrada con el ratón. Las aplicaciones ofimáticas usualmente desplazan por líneas, lo cual se puede conseguir estableciendo a off <code>goSmoothScroll</code>.
  
 
In addition to these <code>Options</code> inherited from <code>TCustomGrid</code> there are some more properties specialized for spreadsheet operation:
 
In addition to these <code>Options</code> inherited from <code>TCustomGrid</code> there are some more properties specialized for spreadsheet operation:

Revision as of 13:20, 20 January 2015

Template:MenuTranslate

Introducción

FPSpreadsheet es un paquete potente para la lectura y escritura de ficheros spreadsheet (Hoja de cálculo). La intención principal es aportar una plataforma capaz de exportar e importar de forma nativa datos a/desde los más importantes formatos de fichero de hojas de cálculo sin tener que instalar aplicaciones adicionales.

Pronto, como siempre, surge el deseo de utilizar este paquete también para editar el contenido y formato. Para este propósito, la librería contiene un control grid (FPSpreadSheetGrid) dedicado, que nos recuerda las características de una hoja de trabajo (WorkSheet) de las aplicaciones de hojas de cálculo. Junto a un conjunto de opciones de formato, esta demo todavía viene a tener 1400 líneas de código en su unidad de formulario principal. Por lo tanto, se ha diseñado un conjunto de controles visuales que simplifican ampliamente la creación de aplicaciones de hoja de cálculo (SpreadSheets).

La intención de este tutorial es escribir un programa de hoja de cálculo simple en base a estos controles.

Aunque la mayor parte de la estructura interna de la librería FPSpreadsheet está cubierta mediante los controles visuales sigue siendo recomendable tener algún conocimiento de FPSpreadsheet. Por supuesto debería tenerse un conocimiento básico de Lazarus o FPC y sobre como trabajar con el inspector de objetos de Lazarus.

Controles Visuales FPSpreadSheet

FPSpreadsheet expone clases no visuales, tales como TsWorkbook, TsWorksheet etc. Esto mantiene la librería suficientemente generalizada para todo tipo de programas Pascal. Por otro lado, para programamas con Interfaz Gráfica de Usuario (GUI: Graphic Unit Interface), se necesita algo de infraestructura que relacione los SpreadSheets con los formularios, grids y otros controles.

TsWorkbookSource

TSWORKBOOKSOURCE.png El corazón de los controles visuales FPSpreadSheet es la clase TsWorkBookSource que aporta un enlace entre los datos no visuales spreadsheet y los controles visuales del formulario. Su propósito es similar al que tiene el componente TDataSource en aplicaciones de base de datos que enlazan las tablas de las bases de datos o consultas (queries) a controles orientados a datos (data-aware).

Todos los controles visuales FPSpreadSheet tienen una propiedad WorkbookSource que los enlaza con la cadena de información aportada por TsWorkbookSource. WorkbookSource mantiene un listado de todos los controles vinculados. Estos controles se llaman internamente "listeners" porque se encuentran en modo escucha de la informa distribuida por WorkbookSource.

El libro de trabajo (WorkBook) y las hojas de trabajo (WorkSheets) que contiene, utilizan eventos para notificar a WorkBookSource todos los cambios relevantes: cambios en el contenido de las celdas o su formato, selección de otras celdas, añadir o borrar hojas de trabajo, etc. La información de estos cambios se pasa a través de los controles "listening" y reaccionan a su propio modo especializado a dichos cambios. Si por ejemplo se añade una hoja de trabajo a un libro, entonces el control visual TsWorkBookTabControl crea una nueva solapa para la hoja de trabajo y el control grid "TsWorksheetGrid" carga la nueva hoja de trabajo dentro de la grid.

Control TsWorkbookTabControl

TSWORKBOOKTABCONTROL.png Es un control tipo solapa (tabcontrol) que provee una solapa para cada hoja de trabajo (WorkSheet)del actual libro de trabajo (WorkBook). Los nombres de las solapas son idénticas a los nombres de las hojas de trabajo. La selección de cualquier otra solapa es comunicada a los otros controles del SpreadSheet a través de WorkbookSource.

TsWorksheetGrid

TSWORKSHEETGRID.png Es un DrawGrid personalizado descendiente del LCL y muestra celdas de la hoja de trabajo actual seleccionada. El texto no se almacena en la grid (como haría un StringGrid), pero se toman de la estructura de datos de TsWorksheet. Similarmente, la hoja de trabajo aporta la información de como está formateada cada celda. Como cualquier otra grid del LCL tiene un conjunto de propiedades y se puede tunear por parte de las aplicaciones adaptando sus Options. La más importante se describe abajo.

Note-icon.png

Nota: TsWorksheetGrid puede ser manejado también sin TsWorkbookSource. Para este propósito provee su propio conjunto de métodos para lectura y escritura de ficheros.

TsCellEdit

TSCELLEDIT.png Las aplicaciones de hoja de cálculo típicas proveen un línea para la edición de fórmulas y contenido de las celdas. Este es el propósito de TsCellEdit. Esto muestra el contenido de la celda activa dentro de la hoja de trabajo la cual es la misma que la que se encuentra activa en el grid de la hoja de trabajo (WorksheetGrid). Si se finaliza la edición (presionando Enter, o seleccionando otra celda en la grid)entonces se transfiere a la hoja de trabajo el nuevo valor de la celda. El control TsCellEdit es internamente del tipo memo que por ejemplo es capaz de procesar múltiples líneas de texto correctametne. Para insertar un forced line-break se puede pulsar la secuencia Ctrl+ Enter.

TsCellIndicator

TSCELLINDICATOR.png This is a TEdit control which displays the address of the currently selected cell in Excel notation, e.g. 'A1' if the active cell is in the first row and first column (row = 0, column = 0). Conversely, if a valid cell address is entered into this control the corresponding cell becomes active.

TsCellCombobox

TSCELLCOMBOBOX.pngEste combobox se puede utilizar para modificar varias propiedades de la celda seleccionando sus valores de una lista desplegable. La propiedad afectada viene determinada por el CellFormatItem del combobox:

  • cfiFontName: el listado contiene los nombres de todas las fuentes disponibles en el sistema. Si se selecciona un elemento de ese listado entonces el tipo de fuente que se ha seleccionado se utiliza para dar formato a la/las celdas que tuviesemos seleccionadas antes de desplegar sus propiedades para cambiarlas.
  • cfiFontSize: este listado contine los tamaños de fuente más comunmente utilizados en hojas de cálculo. Seleccionando un elemento de los disponibles se establece por tanto el tamaño de fuente para la/las celda(s) seleccionadas.
  • cfiFontColor: este listado contiene todos los colores disponibles en la paleta del libro de trabaja (workbook). El color seleccionado se asigna a la fuente de la/las celda(s) seleccionada.
  • cfiBackgroundColor: similar a cfiFontColor - se utiliza el color seleccionado como color de relleno de fondo de la/las celda(s) seleccionadas.

TsSpreadsheetInspector

TSSPREADSHEETINSPECTOR.png Hereda de TValueListEditor y muestra pares nombre-valor (name-value) para propiedades del libro de trabajo, la hoja de trabajo y el contenido y formateado de la celda activa. Su propósito principal es ayudar con el depurado (debugging).

Escribiendo una aplicación de hoja de cálculo

Bueno suficiente teoría hasta aquí, comencemos. Vamos a escribir una pequeña aplicación de hoja de cálculo. Cierto, no va a competir con las principales aplicaciones ofimáticas como Excel u OpenOffice/LibreOffice, pero tiene todos los ingredientes principales asociados a FPSpreadsheet. Y utilizando controles FPSpreadsheet nos permite conseguir esto con unas mínimas líneas de código.

Preparativos

fpspreadsheetcontrols preparations.png

Primero de todo vamos a crear un nuevo proyecto y lo almacenamos en alguna carpeta de nuestra elección.

Ya que las aplicaciones ofimáticas tienen un menú y una barra de utilidades (toolbar) añadimos al formulario los correspondientes componentes TMainMenu y TToolbar

(Se puede incluso mimetizar el ribete del interfaz de usuario de las nuevas aplicacones de Microsoft añadiendo un TSpkToolbar de Lazarus Code and Components Repository, pero ten en cuenta que este componente no provee todavía todas las características de una toolbar standar).


En efecto, necesitaremos otra toolbar para la línea del editor de fórmulas. Como verás más adelante, será redimensionable; como control de tamaño añade un TSplitter al formulario con una alineación top de tal manera que esté posicionado debajo de las dos barras de utilidades. En orden a mantener un tamaño mínimo para la toolbar se establecen restricciones: Mira la altura actual de la toolbar e introduce su valor numérico dentro del campo MinHeight de la propiedad Constraints en la toolbar. Para separar la barra de utilidades (toolbar) de fórmulas del resto del formulario principal, activamos la opción ebBottom de la propiedad EdgeBorders de la segunda toolbar.

Debido a que tanto el menú como las barras de utilidades tienen que manejar las mismas acciones de usuario resulta ventajoso aportar un TActionList para almacenar todas las posibles acciones. Si se asigna a los elementos del menú y a los pulsadores de utilidades (ToolButtons) entonces ambos reaccionarán a la interacción del usuario de la misma manera sin necesidad de código adicional. Y: además los controles visuales del paquete FPSpreadsheet contienen un montón de acciones estandar listas para usar.

La barra de utilidades de la aplicación completa va a contener un montón de iconos. Por tanto necesitamos un componente TImageList el cual tiene que ser enlazado a la propiedad Images del menú principal (TMainMenu), las barras de utilidades (TToolbars), y los listados de acciones (TActionList). A la pregunta de donde obtener iconos la respuesta más fácil es buscar en la carpeta images de la propia instalación de Lazarus donde podemos encontrar iconos estandar para cargar, salvar, salir, flechas, imprimir,configurar,.... Es un subconjunto de la librería de iconos famfamfam SILK. Otra enorme colección se encuentra en la colección de iconos Fugue. Ambas colecciones están licenciadas como "Creative commons" y son libres incluso para su uso comercial, añadiendo la referencia apropiada en los programas creados. Cuando selecciones iconos procura que tengan el formato de imagen png y asegúrate de utilizar siempre el mismo tamaño, usualmente 16x16 pixels.

Setting up the visual workbook

TsWorkbookSource

Tal como se ha descrito en la sección de introducción, el componente TsWorkbookSource es el interface entre WorkBook y los controles de interface de usuario. Se añade por tanto este componente al formulario y se le asigna un nombre decente (en este caso dejaremos el nombre que tiene por defecto sWorkbookSource1). Como veremos en breve, este componente tendrá que ser asignado a la propiedad WorkbookSource de todos los controles del paquete visual FPSpreadsheet_visual.

WorkBookSource se encarga de la carga y escritura de datos desde/hacia el fichero y de la comunicación con WorkBook. Por tanto, posee un conjunto de opciones que se pasan al WorkBook y controla estos procesos:

type
  TsWorkbookOption = (boVirtualMode, boBufStream, boAutoCalc, boCalcBeforeSaving, boReadFormulas);
  TsWorkbookOptions = set of TsWorkbookOption;
sTabControl.png

Los más importantes son:

  • boAutoCalc: activa el cálculo automático de las fórmulas en el momento que cambia el contenido de las celdas.
  • boCalcBeforeSaving: calcula las fórmulas antes de que el WorkBook se escriba al fichero.
  • boReadFormulas: si se establece entonces se leen las fórmulas del fichero, de otro modo solamente el resultado de la fórmula.
  • boBufStream y boVirtualMode: en programas no visuales estas opciones pueden ayudar si las aplicaciones se quedan sin memoria en el caso de workbooks extensos. boVirtualMode, en particular, no es usable para aplicaciones visuales, porque evita guardar datos en las celdas de la hoja de trabajo. Ver también FPSpreadsheet#Virtual_mode.

En este tutorial se asume que las opciones boAutoCalc y boReadFormulas se encuentran activas.

TsWorkbookTabControl

El primer control visual utilizado en el formulario es un TsWorkbookTabControl - lo emplazamos en el formulario (dentro del espacio no ocupado por la ToolBar). Client-align it within the form, this shows the TabControl as a bright rectangle only. Ahora vinculamos su propiedad WorkbookSource al componente TsWorkbookSource que hemos añadido previamente. Ahora TabControl muestra una solapa llamada "Sheet1". Esto es debido a que TsWorkbookSource ha creado WorkBook vacío conteniend una sola hoja (WorkSheet) "Sheet1". WorkbookSource sincroniza este WorkBook interno con TabControl (y el resto de elementos visuales asociados) tal como se muestra la hoja como solapa.

En Excel las solapas de las hojas se encuentran al fondo del formulario - para lograr este efecto se puede establecer la propiedad TabPosition del control TabControl a tpBottom; hay algunas incidencias para el dibujado del LCL con TabPosition, aunque, de ante mano, yo prefiero los valores por defecto, tpTop.

El pantallazo muestra lo que obtenemos.

TsWorksheetGrid

sWorksheetGrid.png

Ahora añadimos un control TsWorksheetGrid. Lo emplazamos en algún lugar dentro del espacio ocupado por el control TabControl. De esta forma viene a colgar de TabControl. Al hacer esto podremos ver algo parecido a un componente grid de cadenas (StringGrid). Enlazamos su propiedad WorkbookSource a la fuente añadida al principio y entonces la grid se parece más a una hoja de cálculo (SpreadSheet): están las cabeceras de las columnas etiquetadas con letras "A", "B", etc, y las filas etiquetadas con números "1", "2", etc; la celda activa, A1, está remarcada por el borde grueso.

Puede que se necesite cambiar TitleStyle a tsNative en la grid para lograr el themed painting de la cabecera de la fila y columna. Y aquí también es un buen lugar para adaptar las Options de la grid para activar algunas características bien conocidas de las hojas de cálculo:

  • goEditing debe estar activo, de otra manera el contenido de la grid no se podrá modificar.
  • goAlwaysShowEditor debe estar off porque interfiere with the editing convention de las aplicaciones de hojas de cálculo.
  • goColSizing habilita cambiar el ancho de columna a través del dragging de la línea divisoria que encontramos en las cabeceras de las columnas adyacentes.. Dragging tiene lugar con el pulsador izquierdo del ratón presionado.
  • goRowSizing realiza lo mismo con la altura de las filas.
  • goDblAutoResize activa la característica de optimización de ancho de columna que se obtiene haciendo doble click en la línea divisoria del encabezado de la columna que se situa hacia al siguente columna. La "optimum" ancho de columna es tal que no se trunca el contenido de la celda y no se muestra espacio extra sobrante.
  • goHeaderHotTack nos da información adicional si se pasa el cursor del ratón por encima de la cabecera de las celdas.
  • goRangeSelect (se encuentra "on" por defecto) y habilita la selección de un rango rectangular de celdas haciendo click con el pulsador izquierdo del ratón y sin soltarlo arrastrandolo hasta completar la selección de celdas (en definitiva de esquina a esquina opuesta del rectángulo). Si se tiene una versión de Lazarus del trunk y incluso se puede realizar una selección multiple de areas rectangulares manteniendo pulsada la tecla CTRL antes de seleccionar el siguente rectángulo - en la versión 1.2.6 de Lazarus (en el momento de estribir esto) solamente se permite la selección de un rango.
  • goThumbTracking activa el scrolling inmediato de la hoja (Worksheet) si una de las barras de desplazamiento es arrastrada con el ratón. Las aplicaciones ofimáticas usualmente desplazan por líneas, lo cual se puede conseguir estableciendo a off goSmoothScroll.

In addition to these Options inherited from TCustomGrid there are some more properties specialized for spreadsheet operation:

  • ShowGridLines, if false, hides the row and column grid lines.
  • ShowHeaders can be set to false if the the column and row headers are to be hidden. (The same can be achieved also by the deprecated property DisplayFixedColRow).
  • The LCL grids normally truncate text at the cell border if it is longer than the cell width. If TextOverflow is set to true then text can overflow into adjacent empty cells.

The properties AutoCalc and ReadFormulas are meant for stand-alone usage of the WorksheetGrid (i.e. without a TsWorkbookSource). Please use the corresponding options of the WorkbookSource instead. (AutoCalc enables automatic calculation of formulas whenever cell content changes. ReadFormulas activates reading of formulas from files, otherwise the grid would display only the formula results).