2

我正在使用David-W-Fenton 对此问题的回答来尝试允许用户在单击控件时打印报告,但我收到以下错误消息:

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 似乎使用上面的代码正确填充。

谁能告诉我如何克服错误消息以便正确加载表单?


正确,完整的答案:


这个问题的答案是大大简化代码。这篇文章顶部链接中的代码太复杂了,它试图重新发明 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 的答案标记为已接受的答案,因为他显然在这方面做了很多工作,对此我非常感激。但我最终用 A LOT LESS CODE 解决了这个问题。我的解决方案不需要自定义对话框表单,因为它使用 Windows 打印对话框表单。因此,我的帖子中的加载事件代码(取自上面的链接)是不必要的。

4

1 回答 1

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 put 上的 OK/Cancel 按钮单击事件(在现有代码之后,但删除“Docmd.close”的任何实例):

Forms!Calling_Form_Name.DialogAccept

然后这会调用该方法,以执行在用户说“我完成了对话”之后应该发生的事情。

最后给dlgPrinter添加configure方法:

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() & mid() 和 instr() 分解 me.Openargs,并将 me.Name 保存到表单上某些内容的标记中(您尚未使用该标记)。

在 OK/Cancel 按钮单击事件中,将上面的代码更改为:

Forms(Object.Tag).DialogAccept
于 2013-11-06T04:03:10.140 回答