[Lazarus] Flexible exporter for grid-like components

Werner Pamler werner.pamler at freenet.de
Sun May 1 21:34:38 CEST 2016


TStringGrid provides the methods SaveToCSVFile/Stream for saving the 
grid content to a csv file or stream. This is very convenient for users, 
but it is not very flexible: The export works only for the csv data 
format, no html, no possibility to plug in other formats. It requires 
always a modification of the /grids /unit to extend these methods by 
additional options. And it works only with TStringGrid - there are other 
grid-like controls, such as custom "virtual" grids derived from 
TCustomDrawGrid, TListview in report mode, TKGrid and other third-party 
grids which are not supported: if they do not have such a method on 
their own the export code has to be re-written (often: duplicated).

The attached file contains code for a flexibile export system for 
2D-data classes which is open and can easily be extended to other 
formats and other controls. It essentially consists of two parts:

  * *TLazExporter *represents the file format. The class is abstract and
    provides the methods to write cells and rows to stream and file. I
    implemented an exporter for *csv *and *html *files for the lclbase
    package. But in addition there is also a dedicated
    SpreadsheetExporter which takes care of *Excel *and/or *Opendocument
    *file formats (using fpspreadsheet).
  * *TLazExporterLink *provides the data to be exported. It is an
    abstract class between the control to be exported and the writer. It
    exposes methods to navigate from cell to cell and row to row, and to
    define the strings assigned to each cell. I implemented a
    TGridExporterLink (accessing *TCustomStringGrid*, in the long run:
    *TCustomDrawGrid*) and *TCustomListView*. The same principle works
    for any other classes with 2D data arrays (matrix).

The unit /GridExporter /exposes functions to write grid content to file 
and to stream. The exporter instance is passed as a parameter, i.e. it 
is very easy to switch from csv to hml or any other format provided the 
corresponding exporter is available.

          procedure ExportGridToFile(AGrid: TCustomStringGrid; 
AExporter: TLazExporter; const AFileName: String; AOptions: 
TGridExportOptions); overload;
          procedure ExportGridToStream(AGrid: TCustomStringGrid; 
AExporter: TLazExporter; AStream: TStream; AOptions: 
TGridExportOptions); overload;

Similarly, there are also ExportListviewToFile/Stream procedures in the 
unit /ListViewExporter /for the export from a TListview.

Properties of the exporter can be used to fine-tune the export. In case 
of the html exporter, for example, a set of css statements can be 
specified to format the exported html table:

          htmlexporter := THTMLExporter.Create;
          with htmlexporter do
          begin
            CSS.Add('table { border: 1px solid #DDDDFF; }');
            CSS.Add('th { background-color: #DDDDFF; }');
            CSS.Add('h1 { font-family:Helvetica, Arial, sans-serif; 
font-size:16pt; color:blue; background-color: #EEEEFF}; }');
         end;
         ExportGridToFile(StringGrid1, exporter, AFileNameForGrid, 
[geoFixedRows, geoFixedCols, geoVisibleColsOnly]);
         ExportListViewToFile(Listview1, exporter, AFileNameForListView, 
[leoTitles, leoVisibleColsOnly]);

In addition to these procedures there are overloaded versions taking the 
exporter class (instead of an exporter instance) as a parameter. In this 
way the default exporter parameters are applied during the export. Of 
course, these procedures can be added as methods to the classes referred 
to by the first parameter.

The attached demo shows the exporter system at work. It requires no 
modification of any LCL packages or units. In the long run, however, I'd 
propose to add unit /LazExporter /to package /LazUtils /and 
/GridExporter /and /ListviewExporter /to package /LclBase 
/(/SpreadsheetExporter /would go to /laz_//fpspreadsheet/), and to make 
these modifications to the /grids /unit:

  * Extend the ExportGridToFile/Stream procedures to accept also
    TCustomDrawGrid descendants. This would be possible by introducing a
    virtual method GetCellText(Col,Row) to TCustomDrawGrid (or maybe
    even TCustomGrid) which would catch the cell text from a special
    event OnGetCellText; this would help to create "virtual" grids using
    TCustom(Draw)Grids. In case of the TStringGrid, of course,
    GetCellText would simply return the cell strings Cells[Col, Row].
  * Replace the code in SaveToCSVFile/Stream by the csv exporter. I'd
    also vote to deprecate these methods because they are special cases
    of the csv exporter.
  * Replace the copy-to-clipboard code (CopyCellRectToClipboard) by the
    csv exporter. In addition, a html format could be written to the
    clipboard with almost no extra code.

I would greatly appreciate any comments.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus-ide.org/pipermail/lazarus/attachments/20160501/50995bce/attachment-0002.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: exporters.zip
Type: application/x-zip-compressed
Size: 14039 bytes
Desc: not available
URL: <http://lists.lazarus-ide.org/pipermail/lazarus/attachments/20160501/50995bce/attachment-0002.bin>


More information about the Lazarus mailing list