runtime error 2448 you cant assign a value to this object

12,172

The code posted cannot work, because when a form is opened as a dialog:

DoCmd.OpenForm "dlgPrinter", , , , , acDialog, strReport

no other logic after this line is executed until the form has been closed, at which point control returns to the next line after this one, and logic continues on - except of course you can no longer reference anything in that form, because it is now closed.

Ok, now there is a question, where is the button the user clicks to print a report?

What I'm thinking is to split the logic in PrintReport into two methods, one that launches it, and tells the form to configure itself (doing the stuff suggested in the comment), but the rest of PrintReport then needs to happen after the user clicks OK (or Cancel);

So if I assume that you've got a form which can launch one or more reports, and the button is on this form, what I would suggest is this:

In the click event for that button - no changes to what you've got.

In that buttons form, add this:

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

Change PrintReport to:

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

In the OK/Cancel button click events on dlgPrinter put (after existing code, but removing any instances of "Docmd.close"):

Forms!Calling_Form_Name.DialogAccept

This then calls that method, to do the stuff that is meant to happen after the user says "I'm done with the dialog".

Finally add the configure method to 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

And remove this code section from Form_Load.

Hoep this helps.

Lastly, if the form on which the button launching dlgPrinter can vary, change this line:

DoCmd.OpenForm "dlgPrinter", , , , , acDialog, strReport

to:

DoCmd.OpenForm "dlgPrinter", , , , , acDialog, strReport & ";" & me.Name

In form_load of dlgPrinter, break up me.Openargs using left() & mid() with instr(), and save me.Name into the tag of something on the form (which you're not already using the tag of).

In the OK/Cancel button click events, change the code above to:

Forms(Object.Tag).DialogAccept
Share:
12,172
CodeMed
Author by

CodeMed

Updated on June 04, 2022

Comments

  • CodeMed
    CodeMed almost 2 years

    I am using David-W-Fenton's answer to this question to try to allow users to print a report when they click on a control, but I am getting the following error message:

    runtime error 2448: you cannot assign a value to this object.
    

    The line of code triggering the error is:

    Me.txtPageTo.Value = numPages  
    

    Here is the full code of the OnLoad event handler for the form:

    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 prints out to equal 0 just before the error is thrown, even though the report should have at least one page. Also, the error does not get thrown when the form is already open. The error only gets thrown when the form has to be opened. (Probably because the offending code is in the onload event.)

    When I added TypeName(Me.txtPageTo) , it triggered runtime error 2424: The expression you entered has a field, control, or property name that mydatabasename cant find.

    I think the problem is that I need to set the control source for txtPageFrom and txtPageTo. But how do I do that? This form will only be loaded by a vba method that is trying to print a report, so the values for txtPageFrom and txtPageTo will come from the calling method, not from some underlying data table. (there is no underlying data table for this dialog form.)

    cmbPrinter and optLayout seem to be populating correctly using the code above.

    Can anyone show me how to get past the error messages so that the form loads properly?


    CORRECT, COMPLETE ANSWER:


    The answer to this problem was to greatly simplify the code. The code in the link at the top of this posting is WAY TOO COMPLEX, and tries to reinvent things that are already done well by the tools built into Access and VBA. I was able to print reports without any of the complicated solutions by simply using the following code in the on-click event of a control on a form associated with the report:

    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  
    

    That is all the code that was required. Much less than the link at the start of this question. And also much less than the answer below. I am marking John Bingham's answer as the accepted answer because he clearly worked a lot on this, and I am very grateful for that. But I ended up solving the problem with A LOT LESS CODE. My solution does not require the custom dialog form because it uses the Windows print dialog form. As such, the on load event code in my posting (taken from the link above), is not necessary.

    • John Bingham
      John Bingham over 10 years
      You need to put the code assigning the value to this object into the on format event for the section in which this object exists. (Had this problem yesterday!)
    • John Bingham
      John Bingham over 10 years
      Ok obviously from your description, the control is unbound. I would have expected it to work, but drop the .Value out of the statement so it is just: txtPageTo = numpages. Does this help?
    • John Bingham
      John Bingham over 10 years
      What is numPages? ie what does debug.print show?
    • John Bingham
      John Bingham over 10 years
      Also add this line: debug.Print Me.Name - what does this give you?
    • John Bingham
      John Bingham over 10 years
      Whatever causes the form to open - say the user clicks some button or other, in that button's click event, do this: DoCmd.OpenForm dlgPrinter, ... (dont open as a dialog) and then, Forms("dlgPrinter").Configure. Add a configure method to dlgPrinter (make it a Public Sub). Move the initialisation of the numPages control to Configure. Hope this helps
    • Gord Thompson
      Gord Thompson over 10 years
      Thanks for letting us know the outcome. I had a gut feeling that there was a "keep it simple (or simpler, anyway)" solution lurking out there somewhere.
    • Gord Thompson
      Gord Thompson over 10 years
      Try replacing acWindowNormal, acHidden with just acHidden. (They are both WindowMode constants, so you really should be specifying one or the other, not both.)
    • Gord Thompson
      Gord Thompson over 10 years
      Well, acIcon is the only other WindowMode that looks like it might be worth a try. Personally, I always just open reports in Preview mode and let the user click the Print button (or hit [Ctrl-P]). They never seem to complain.
    • radsdau
      radsdau over 8 years
      This is most helpful to me for another reason. I previously used DoCmd.Printout to print reports, which is a nuisance because the job goes straight to the default printer. Using DoCmd.RunCommand acCmdPrint pops up the printer dialog first- exactly what I needed. Thanks for the tip CodeMed. Would you believe there is no mention of this in the DoCmd.PrintOut help page on MSDN? (I added one)
  • CodeMed
    CodeMed over 10 years
    Thank you again. I am marking this as the correct answer because you spent so much time and energy on this. But I ended up finding a MUCH simpler solution, which I posted at the end of my original posting above.