在 Delphi 应用程序中,多年来我一直使用以下代码将 xlxs 导出为 pdf:
function TExportTool.ExportExcelToPDF(aFileName, aNewFileName: String): Boolean;
// reference : http://embarcadero.newsgroups.archived.at/public.delphi.oleautomation/200811/081103142.html
// unluckily the link above is dead
{- Sheet is counted from 1 and upwards !! }
Var
App,oWB,oSheet : OleVariant;
begin
Result := False;
App:= CreateOleObject('Excel.Application');
Try
App.Visible:= 0;
oWb := App.WorkBooks.Open(ExpandUNCFileName(afilename),1); // Open read only
Try
oSheet := oWB.ActiveSheet;
oSheet.ExportAsFixedFormat(0, //xlTypePDF is constant 0
aNewFileName,
EmptyParam,
EmptyParam,
EmptyParam, // this should be IgnorePrintAreas
EmptyParam,
EmptyParam,
EmptyParam,
EmptyParam
);
Finally
End;
Result := True;
Finally
App.Quit;
App:= UnAssigned;
End;
end;
// IMPROVED WORKING CODE FOLLOWS
function TExportTool.ExportExcelToPDF(aFileName, aNewFileName: String): Boolean;
// reference : http://embarcadero.newsgroups.archived.at/public.delphi.oleautomation/200811/081103142.html
{- Sheet is counted from 1 and upwards !! }
procedure RestoreOriginalPrintArea (oSheet: OleVariant);
// Excel loses print area settings in non-English version of application when file is opened using automation:
// https://stackoverflow.com/questions/71379893/exportasfixedformats-ignoreprintareas-parameter-seems-not-to-have-effect
var
i:Integer;
begin
for i:= 1 to oSheet.Names.Count do
begin
if VarToStr(oSheet.Names.Item(i).Name).EndsWith('!Print_Area') then
begin
oSheet.PageSetup.PrintArea:='Print_area';
Break;
end;
end;
end;
Var
App,oWB,oSheet : OleVariant;
i:Integer;
begin
Result := False;
App:= CreateOleObject('Excel.Application');
Try
App.Visible:= 0;
oWb := App.WorkBooks.Open(ExpandUNCFileName(afilename),1); // Open read only
Try
oSheet := oWB.ActiveSheet;
RestoreOriginalPrintArea(oSheet); // workaround
oSheet.ExportAsFixedFormat(0, //xlTypePDF is constant 0
aNewFileName,
0, // standard quality = 0, Max quality = 1
false, //include doc properties
false, //ignore print area
EmptyParam,
EmptyParam,
EmptyParam,
EmptyParam
);
Finally
End;
Result := True;
Finally
oWB.Close(false); // better to close the WorkBook too
App.Quit;
App:= UnAssigned;
End;
end;
现在我意识到使用此代码创建的 pdf 的行为类似于使用“忽略打印区域”选项从 Excel 保存到 pdf 时(这是从 Excel 功能导出到 pdf 的选项之一)。
所以我决定也从代码中“取消选中”该复选框,并研究了 ExportAsFixedFormat
的参数(引用 here)。
第五个参数是IgnorePrintAreas
,所以我假设将 False 传递给它,打印区域将被忽略。
我尝试了几种常识性解决方案,包括:
- 仅传递该参数(传递 True 或 False )
- 传递所有前 5 个参数(以防它们在运行时是必需的)
但没有结果:我的应用程序创建的 pdf 仍然“忽略打印区域”。
有没有人有关于这个特定主题的建议或经验来指导我解决这个问题?
谢谢。
更新
感谢我将有用的已接受答案附加到解决方案上方的代码以供引用,请注意两件事:
- 包含解决方法的 RestoreOriginalPrintArea 过程
- 最后调用 oWB.Close(false)
最佳答案
错误的根本原因:
当使用自动化打开文件时,Excel 在非英语版本的应用程序中丢失打印区域设置。
为什么会这样:
当您在工作表中定义打印区域时,Excel 会在内部创建一个 named range .它有两个定义其名称的属性:
Name
此属性始终采用WorksheetsName!Print_Area
的形式(如果工作表的名称包含一些特殊字符,它也包含在单引号中)。NameLocal
具有相似的结构,但第二部分被翻译成应用程序的语言。
这就是当您在 Excel 中打开文件并在 VBA 中检查这些属性时的样子,但是当您使用自动化打开同一文件(例如使用有问题的代码)时,NameLocal
不再翻译。此错误导致命名范围无法被正确识别为打印区域。 oSheet.PageSetup.PrintArea
返回空字符串。
解决方法:
使用以下方法打开文件后恢复原始打印区域:
oSheet.PageSetup.PrintArea:='Print_Area';
当sheet中没有定义打印区域时,这行代码会抛出异常,所以有两种选择:
- 将此行放在
try
..except
block 中。 - 迭代
Names
集合并查找以!Print_Area
结尾的Name
,例如:
var i:Integer;
for i:= 1 to oSheet.Names.Count do
begin
if VarToStr(oSheet.Names.Item(i).Name).EndsWith('!Print_Area') then
begin
oSheet.PageSetup.PrintArea:='Print_area';
Break;
end;
end;
其他重要变化:
因为文件可能已被修改,您还需要添加:
oWB.Close(false);//不保存更改
在关闭应用程序之前,否则每次调用此函数都会导致另一个 Excel 进程仍在运行而不可见。
关于delphi - ExportAsFixedFormat 的 IgnorePrintAreas 参数好像没有效果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71379893/