Is it possible to export a VirtualStringTree to Excel or CSV?
I am using Delphi 2007 and trying to save my VirtualStringTree data records as Excel or CSV format.
We have an ExcelWriter
helper class, that can dump all kinds of things to Excel, e.g.
In this case the fast way (and easy to copy-paste here) is the overload that can dump a variant array into Excel:
class function TExcelWriter.ExportToExcelVariantArray(const VArray: Variant; const Title, SubTitle: WideString): Boolean;
var
xl: OleVariant;
workbook: OleVariant;
worksheet: OleVariant;
range: OleVariant;
Rowcount, ColumnCount: Integer;
HeaderRowIndex: Integer;
s: WideString;
begin
Result := False;
if not VarIsArray(VArray) then
raise EExcelWriterException.Create('ExportToExcelVariantArray: Supplied variant is not an array');
if VarArrayDimCount(VArray) <> 2 then
raise EExcelWriterException.Create('ExportToExcelEVariantArray: Supplied variant array does not have 2 dimensions ('+IntToStr(VarArrayDimCount(VArray))+')');
ColumnCount := VarArrayHighBound(VArray, 2) - VarArrayLowBound(VArray, 2); //2 for "leftmost dimension"
rowCount := VarArrayHighBound(VArray, 1) - VarArrayLowBound(VArray, 1); //1 for "leftmost dimension"
try
xl := CreateOleObject('Excel.Application');
except
on E:Exception do
begin
if (E is EOleSysError) then
begin
if EOleSysError(E).ErrorCode = CO_E_CLASSSTRING then
raise EExcelWriterException.Create('Excel is not installed.'+CRLF+
'Could not load "Excel.Application" object (Co_E_CLASSSTRING)')
else
raise;
end
else
raise;
end;
end;
try
xl.ScreenUpdating := False;
xl.DisplayAlerts := False; // Don't display dialogs such as "save changes to workbook".
workbook := xl.Workbooks.Add;
try
Worksheet := Workbook.Worksheets[1];
try
Worksheet.Activate;
Worksheet.Cells.WrapText := False;
HeaderRowIndex := 1; //Rows&Columns in Excel start at one.
range := TExcelWriter.GetRange(worksheet, HeaderRowIndex, 1, HeaderRowIndex+RowCount, ColumnCount);
range.Value := VArray;
//Bold the header row
Worksheet.Rows[HeaderRowIndex].Font.Bold := True;
Worksheet.Rows[HeaderRowIndex].Font.Underline := True;
Worksheet.Columns.AutoFit;
//Set printed header&footer
if Copy(Title, 1, 2) = '@@' then
s := Copy(Title, 3, MaxInt)
else
s := Title;
if SubTitle <> '' then
begin
if s <> '' then s := s+#13;
s := s + SubTitle;
end;
TExcelWriter.SetHeaderAndFooters(Worksheet,
s, '', '',
'&D &T', '', 'Page &P of &N');
finally
Worksheet := Unassigned;
end;
finally
Workbook := Unassigned;
end;
//When all done
xl.ScreenUpdating := True;
xl.Visible := True;
xl.UserControl := True; // Very important, prevents Excel from going
// away when we nil out our reference to it below.
finally
xl := Unassigned;
end;
Result := True;
end;
We have a TVirtualListView
descendant of TVirtualStringTree
that made it easy to transition to VirtualTrees (it has TVirtualListItem
, etc). It then has a helper method ContentToVariantArray
, which is similar to ContentToHtml
and ContentToRtf
:
function TVirtualListView.ContentToVariantArray: Variant;
var
Columns: TColumnsArray;
VArray: Variant;
Node: PVirtualNode;
ColumnCount: Integer;
RowCount: Integer;
nRow: Integer;
i: Integer;
begin
Columns := Self.Columns.GetVisibleColumns;
ColumnCount := Length(Columns);
RowCount := Self.Items.Count+1; //+1 for the heaader
VArray := VarArrayCreate([0, RowCount-1, 0, ColumnCount-1], varOleStr); //Docs say cannot use varString, must be varOleStr (which is a BSTR i.e. WideString)
nRow := 0;
for i := 0 to ColumnCount-1 do
begin
VArray[nRow, i] := Self.Columns.Items[Columns[i].Index].Text;
end;
Node := Self.GetFirst;
while Assigned(Node) do
begin
Inc(nRow);
for i := 0 to ColumnCount-1 do
begin
VArray[nRow, i] := Self.Text[Node, Columns[i].Index];
end;
Node := Self.GetNextSibling(Node);
end;
Result := VArray;
end;
The main downside here is that we're automating Excel in order to use it. This means your customer/server will need Excel installed.
The above code shows the user Excel (having to save a file to the hard drive just to look at it is wasteful), rather than creating an export file. But wouldn't be hard to call .Save
or whatever the API is.
CSV Would be easier.
Your data is your own data, since the VirtualStringTree does not contain data, it is a virtual container. So, if your virtual string tree is a view of a TMyObjects list (container), it should be relatively trivial to output to CSV, and the content of the Virtual Tree would only really matter if your columns could be in a different order, or the set of columns that are visible are done.
I suggest you investigate the free JVCL JvCsvDataSet which is a really easy way to write CSV files.
If you really want XLS output, there are libraries for that.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With