我有一份非常VBA密集的报告。当我预览它时,一切都很棒但是当我在预览之后打印它时会变得古怪。我花了很多时间来缩小可能性,并且我确信这是MS Access中的一个错误。
到目前为止,我打印报告的方法是使用docmd.openreport "report"
打开报告。然后我使用docmd.printout
命令,以便我可以设置页面范围,整理等。
有没有办法直接打印报告,仍然可以设置页面范围,整理等选项而无需先进行预览?
谢谢, 杰夫
答案 0 :(得分:3)
遗憾的是,没有办法完全在代码中完成它,但自从引入DoCmd.OpenReport方法的WindowMode参数以来,它仍然可以完成。这使得可以在打印预览模式下打开报告并将其隐藏。然后,您可以设置报表的Printer对象的属性(例如输出打印机和方向),然后使用DoCmd.PrintOut打印页面范围。
有一点需要注意:
您无法在报表的OnOpen事件中执行此操作,因为更改对布局有影响的任何内容都不会为您提供正确的结果。例如,如果在OnOpen事件中,您从纵向更改为横向,则无法准确计算报表中有多少页面,因为在OnOpen事件触发时尚未格式化报表。但是对于除页面之外的所有内容,它都可以。
我实现这一点的方法是使用公共函数和对话框表单。该函数看起来像这样:
Public Function PrintReport(strReport As String) As Boolean
' open report in PREVIEW mode but HIDDEN
DoCmd.OpenReport strReport, acViewPreview, , , acHidden
' open the dialog form to let the user choose printing options
DoCmd.OpenForm "dlgPrinter", , , , , acDialog, strReport
With Forms!dlgPrinter
If .Tag <> "Cancel" Then
Set Reports(strReport).Printer = Application.Printers((!cmbPrinter))
Reports(strReport).Printer.Orientation = !optLayout
Application.Echo False
DoCmd.SelectObject acReport, strReport
DoCmd.PrintOut acPages, !txtPageFrom, !txtPageTo
PrintReport = True
End If
End With
DoCmd.Close acForm, "dlgPrinter"
DoCmd.Close acReport, strReport
Application.Echo True
End Function
对话框表格如下所示:
alt text http://dfenton.com/DFA/examples/PrinterProperties.png
如上所示,我使用OpenArg参数打开此对话框,该参数是报告的名称。在对话框的OnLoad事件中,我初始化窗体上的控件:
Dim varPrinter As Printer
Dim strRowsource As String
Dim strReport As String
If Len(Me.OpenArgs) > 0 Then
strReport = Me.OpenArgs
Me.Tag = strReport
For Each varPrinter In Application.Printers
strRowsource = strRowsource & "; " & varPrinter.DeviceName
Next varPrinter
Me!cmbPrinter.RowSource = Mid(strRowsource, 3)
' first check to see that the report is still open
If (1 = SysCmd(acSysCmdGetObjectState, acReport, strReport)) Then
With Reports(strReport).Printer
Me!cmbPrinter = .DeviceName
Me!optLayout = .Orientation
End With
Me!txtPageTo = Reports(strReport).Pages
End If
End If
我使用表单的.Tag属性作为报告名称,然后根据该属性执行所有操作,包括动态更改报告属性,这可能是因为报告在预览模式下打开但不可见。 / p>
例如,我在布局选项组后面有这个AfterUpdate事件:
With Reports(Me.Tag)
.Printer.Orientation = Me!optLayout
Me!txtPageTo = .Pages
End With
我更改页面范围编号的原因是更改方向很可能会更改页面数。与OnOpen事件不同,对打印预览模式中无形打开的报表格式属性的更改会立即发生。
我使用标准方法进行对话框表单,即使用“取消”和“继续”按钮将表单的.Visible属性设置为False,这样可以继续调用代码。对于“取消”按钮,我将表单的.Tag属性设置为“取消”,并在代码在调用上下文中继续时检查.Tag属性(参见上文)。
因此,这并不像能够直接在Printer对象上设置页面范围那样好,但它可以完成工作。
生产代码中需要更改的一件事是确保PrintReport函数中有一个错误处理程序,这样如果出现问题,可以重新打开Application.Echo(否则,用户可能会被困在一个空白的屏幕,无法工作)。另一种方法是在调用DoCmd.SelectObject方法时让报告显示在屏幕上。但是,如果我正在隐藏用户的报告预览,我会想要一路走下去。
有关此内容的更多信息,您应该调查对象浏览器中的.Printer对象(VBE中的F2),MS Knowledge Base article 290293有助于解释Application.Printers集合和Application.Printer对象之间的交互。以及与特定报告相关的那些。我还发现a little tutorial on the Office site澄清了一些事情。
答案 1 :(得分:1)
很久以前,我遇到了一个非常困难的案子。我不得不做一些场地创作,移动和格式化,这只能以一种方式完成。我采取了大胆的方法,它变成了唯一的方式:我打开隐藏的报告并在设计模式下,让vba做它的东西,完成后,报告变为正常,可见,用于显示和打印。
答案 2 :(得分:0)
一种解决方案是在报告设计中设置打印机选项,保存这些更改并进行打印。缺点是这会将报告绑定到特定的打印机,除非您进入设计并进行更改。
DoCmd.OpenReport "ReportName", acViewDesign, Null, Null, acHidden
Dim oRpt As Report
Set oRpt = Reports(0)
oRpt.UseDefaultPrinter = False
oRpt.Printer = Application.Printers("printer name")
With oRpt.Printer
.PaperBin = acPRBNAuto
.PaperSize = acPRPSLetter
.Copies = 1
.PrintQuality = acPRPQMedium
End With
DoCmd.Close acReport, "ReportName", acSaveYes
DoCmd.OpenReport "ReportName", acViewNormal
Set oRpt = Nothing