Am 01.05.2016 um 21:34 schrieb Werner Pamler:
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.
In preparing a patch for a Mantis feature request I came across this
issue: fpc does already contain a series of exporters
(packages/fcl-db/export, component palette "Data Export"), among them a
TCSVExporter, TSimpleXMLExporter etc. Since they focus on database
export there is no overlap with the new exporters primarily. But they
make things a lot more complicated...
The easiest way would be to stay with the "two exporter" solution, one
set for database, the other one for non-database export. The new
exporters could be renamed to contain a prefix "Laz" in their name, or
"Text", or "NonDB", or similar.
On the other hand, it should be possible to generalize the fcl exporters
such that they support also non-database sources. This would avoid a lot
of code duplication, and it would present a clearer class hierarchy for
data export to the user. BUT: A lot of refactoring of the corresponding
fcl code is involved in this solution. Therefore, since Lazarus will
support the last pre-3.0 version of fpc for a long time, this solution
will not be available in a Lazaraus released version for the next couple
of years...
What's your opinion out there?
--
_______________________________________________
Lazarus mailing list
Lazarus@lists.lazarus.freepascal.org
http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus