Registriert seit: 9. Sep 2002
Ort: Oelsnitz, Vogtland
43 Beiträge
Delphi 12 Athens
|
AW: Suche Datensenitive ExportToExcel-Funktion
4. Jul 2012, 09:38
Das Problem liegt in der Implementierung: Excel erwartet für Range.Value eine Variante. Wenn Du einen String übergibst, dann wandelt den die Excel-Logik um - und das führt zu den beschriebenen Problemen.
Ich hatte das Problem bei TJVGExportExcel aus JVCL Globus, da war genau so vorgegangen worden.
Die lösung war, die Source zu ändern:
Code:
if ForceTextFormat or
(Dataset.Fields[I].Datatype in [ftString,ftMemo,ftFmtMemo,ftFixedChar,ftWideString,ftGuid
,ftFixedWideChar,ftWideMemo,ftBoolean,ftVariant,ftUnknown
,ftBytes,ftVarBytes,ftBlob,ftGraphic,ftParadoxOle
,ftDBaseOle,ftTypedBinary,ftCursor,ftADT,ftArray,ftReference
,ftDataSet,ftOraBlob,ftOraClob,ftInterface,ftIDispatch,ftOraInterval
,ftConnection,ftParams,ftStream])or
(Dataset.Fields[I].IsNull) then Sheet.Cells[RecNo, ColNo + I] := GetFieldValue(DataSet.Fields[I])
Else Sheet.Cells[RecNo, ColNo + I].Value :=GetFieldValueVar(DataSet.Fields[I]);
In der ursprünglichen Implementierung wurde nur die Funktion GetFieldValue aufgerufen:
Code:
function TJvgCommonExport.GetFieldValue(const Field: TField): string;
begin
if jeoOutputFormattedStrings in Options then
Result := Field.DisplayText
else
Result := Field.AsString;
if Assigned(FOnExportField) then
FOnExportField(Self, Field, Result);
if FTransliterateRusToEng then
Result := Transliterate(Result, True);
if (FMaxFieldSize > 0) and (Field.DataType in [ftString, ftMemo, ftFmtMemo]) then
if Length(Result) > FMaxFieldSize then
Result := Copy(Result, 1, FMaxFieldSize) + '...';
end;
Konkret tritt das Problem bei Gleitkommazahlen und BCD auf, weil bei Field.AsString ein Punkt ausgegeben wird, anstelle eines Komma. Die Funktion GetFieldValueVar übergibt daher eine Variante:
Code:
function TJvgCommonExport.GetFieldValueVar(const Field: TField): Variant;
//Erweiterung zum korrekten export von Nicht-Zeichenkettendaten.
var i:Int64;d:DWord;
begin
if jeoOutputFormattedStrings in Options then Begin
Result := Field.DisplayText;
Exit;
End;
if Field.DataType in [ftSmallint,ftInteger,ftWord,ftAutoInc,ftShortint,ftByte] then Result:=Field.AsInteger
Else if Field.Datatype=ftLargeint Then Result:=Field.Value
Else if Field.DataType=ftLongWord Then Begin
d:=Field.Value;
i:=d;
Result:=i;
End Else if Field.DataType in [ftFloat,ftExtended] Then Result:=Field.AsExtended
Else if Field.DataType = ftCurrency Then Result:=Field.AsCurrency
Else if Field.DataType in [ftBCD,ftFMTBcd] Then Result:=BcdToDouble(Field.AsBCD)
Else if Field.DataType in [ftDate,ftTime,ftDateTime,ftTimeStamp,ftOraTimeStamp] Then Result:=Field.AsDateTime
Else Result:=Null;
// if Assigned(FOnExportField) then FOnExportField(Self, Field, Result); //Abgeschaltet, da hier zwingend ein String erwartet wird.
end;
Allerdings ist hier anzumerken, daß der export von 16T Tupeln mit 60 Spalten ewig dauerte - nach 2 Stunden habe ich den abgebrochen. Verwende nun die Native Excel Suite, da ist der Export dieser Datenmenge nach 20 Sekunden fertig.
Thomas Völker
|