我正在使用David-W-Fenton's answer to this question 尝试允许用户在点击控件时打印报告,但我收到以下错误消息:
runtime error 2448: you cannot assign a value to this object.
触发错误的代码行是:
Me.txtPageTo.Value = numPages
以下是表单的OnLoad事件处理程序的完整代码:
Private Sub Form_Load()
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
Dim numPages As String
numPages = Reports(strReport).Pages
Debug.Print "numPages = " & numPages
TypeName(Me.txtPageTo) 'added this line as a test after
Me.txtPageTo.Value = numPages
End If
End If
End Sub
numPages在抛出错误之前打印出等于0,即使报告至少应有一个页面。此外,当窗体已打开时,不会抛出错误。只有在必须打开表单时才会抛出错误。 (可能是因为有问题的代码在onload事件中。)
当我添加TypeName(Me.txtPageTo)时,它触发了运行时错误2424:您输入的表达式具有 mydatabasename 无法找到的字段,控件或属性名称。
我认为问题是我需要为txtPageFrom和txtPageTo设置控件源。但是我该怎么做?此表单只会由尝试打印报表的vba方法加载,因此txtPageFrom和txtPageTo的值将来自调用方法,而不是来自某些基础数据表。 (此对话框表单没有基础数据表。)
cmbPrinter和optLayout似乎使用上面的代码正确填充。
有人能告诉我如何通过错误消息以便正确加载表单吗?
正确,完整的答案:
这个问题的答案是大大简化代码。此帖子顶部链接中的代码是WAY TOO COMPLEX,并尝试通过Access和VBA中内置的工具重新发明已经完成的事情。通过在与报表关联的表单上的控件的单击事件中使用以下代码,我能够打印没有任何复杂解决方案的报表:
Private Sub txtPrintReport_Click()
On Error GoTo Error_Handler
Dim commNum As Long
commNum = Me.CommunicationNumber
Dim strReport As String
Dim strVarName As String
strReport = "rptCommunicationFormForPrinting"
strVarName = "CommunicationNumber"
DoCmd.OpenReport strReport, acViewPreview, , strVarName & " = " & commNum, acWindowNormal, acHidden
DoCmd.RunCommand acCmdPrint
DoCmd.Close acReport, strReport
Exit_Point:
Exit Sub
Error_Handler: 'this handles the case where user clicks cancel button
If Err.Number <> 2501 Then
MsgBox Err.Description, _
vbExclamation, "Error " & Err.Number
End If
DoCmd.Close acReport, strReport
End Sub
这就是所需的所有代码。远远低于这个问题开头的链接。而且比下面的答案要少得多。我将John Bingham的答案标记为已接受的答案,因为他在这方面做了很多工作,我非常感激。但我最终用一个很少的代码解决了这个问题。我的解决方案不需要自定义对话框表单,因为它使用Windows打印对话框表单。因此,我的发布中的加载事件代码(取自上面的链接)不是必需的。
答案 0 :(得分:2)
发布的代码不起作用,因为当窗体作为对话框打开时:
DoCmd.OpenForm "dlgPrinter", , , , , acDialog, strReport
在执行此行之前没有其他逻辑,直到表单关闭,此时控件返回到此行之后的下一行,并且逻辑继续 - 除了当然您不能再引用该表单中的任何内容,因为它现在已关闭。
好的,现在有一个问题,用户点击打印报告的按钮在哪里?
我在想的是将PrintReport中的逻辑拆分为两个方法,一个启动它,并告诉表单自行配置(执行注释中建议的内容),但PrintReport的其余部分则需要发生用户单击“确定”(或“取消”)后;
因此,如果我假设您有一个可以启动一个或多个报告的表单,并且该按钮位于此表单上,我建议的是:
在该按钮的点击事件中 - 不会改变您所拥有的内容。
在该按钮表单中,添加以下内容:
Public Sub DialogAccept()
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 Sub
将PrintReport更改为:
Public Function PrintReport(strReport As String, strVarName As String, numVal As Long) As Boolean
' open report in PREVIEW mode but HIDDEN
DoCmd.OpenReport strReport, acViewPreview, , strVarName & " = " & numVal, acHidden
'DoCmd.OpenReport strReport, acViewPreview, , , acHidden
' open the dialog form to let the user choose printing options
DoCmd.OpenForm "dlgPrinter", , , , , , strReport
Forms!dlgPrinter.Configure
End Function
在确定/取消按钮中单击dlgPrinter上的事件(在现有代码之后,但删除“Docmd.close”的任何实例):
Forms!Calling_Form_Name.DialogAccept
然后调用该方法,在用户说“我已完成对话框”之后执行要发生的事情。
最后将配置方法添加到dlgPrinter:
Public Sub Configure()
With Reports(Me.Tag).Printer
Me!cmbPrinter = .DeviceName
Me!optLayout = .Orientation
End With
Dim numPages As String
numPages = Reports(Me.Tag).Pages
Debug.Print "numPages = " & numPages
TypeName(Me.txtPageTo) 'added this line as a test after
Me.txtPageTo.Value = numPages
End Sub
从Form_Load中删除此代码部分。
这会有所帮助。
最后,如果按钮启动dlgPrinter的表单可能会有所不同,请更改此行:
DoCmd.OpenForm "dlgPrinter", , , , , acDialog, strReport
为:
DoCmd.OpenForm "dlgPrinter", , , , , acDialog, strReport & ";" & me.Name
在dlgPrinter的form_load中,分解我。使用left()&amp; amp; mid()with instr(),并将me.Name保存到表单上的某些内容的标记中(您尚未使用该标记)。
在“确定/取消”按钮中单击“事件”,将上面的代码更改为:
Forms(Object.Tag).DialogAccept