InvokeLater error

I have finally managed to write a script module that opens a page, grabs the report viewer as a pfd, saves it and then closes the window. I am running this off of a button on screen. Everything I read regarding this tells me I should use the invokelater function but if I have this at the bottom of the script I get the error message:

[quote]Traceback (innermost last):
File “event:actionPerformed”, line 1, in ?
ImportError: Error loading module test3: null

at org.python.core.Py.ImportError(Py.java)
at com.inductiveautomation.ignition.common.script.ScriptModule.loadModule(ScriptModule.java:46)
at com.inductiveautomation.ignition.common.script.ScriptPackage.__findattr__(ScriptPackage.java:59)
at org.python.core.PyObject.__getattr__(PyObject.java)
at org.python.pycode._pyx68.f$0(<event:actionPerformed>:1)
at org.python.pycode._pyx68.call_function(<event:actionPerformed>)
at org.python.core.PyTableCode.call(PyTableCode.java)
at org.python.core.PyCode.call(PyCode.java)
at org.python.core.Py.runCode(Py.java)
at com.inductiveautomation.ignition.common.script.ScriptManager.runCode(ScriptManager.java:391)
at com.inductiveautomation.factorypmi.application.binding.action.ActionAdapter.runActions(ActionAdapter.java:139)
at com.inductiveautomation.factorypmi.application.binding.action.ActionAdapter.invoke(ActionAdapter.java:247)
at com.inductiveautomation.factorypmi.application.binding.action.RelayInvocationHandler.invoke(RelayInvocationHandler.java:55)
at $Proxy1.actionPerformed(Unknown Source)
at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
at java.awt.Component.processMouseEvent(Unknown Source)
at javax.swing.JComponent.processMouseEvent(Unknown Source)
at java.awt.Component.processEvent(Unknown Source)
at java.awt.Container.processEvent(Unknown Source)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Window.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)

Ignition v7.2.2 (b6567)
Java: Sun Microsystems Inc. 1.6.0_20[/quote]

Below is my file, if I remove the # from the invokelater line it errors, without the invoke the code works perfectly

[code]def test():
import system

open window with report on it

system.nav.openWindow('AP7_Power_Reports/Biscuit_Report')

open window with report on it

system.nav.openWindow('AP7_Power_Reports/Biscuit_Report')

declare “window” as the window name. You cannot just use event.source.parent etc

window = system.gui.getWindow('AP7_Power_Reports/Biscuit_Report')

declare “report” as the Report Viewer (same reason as line above)

report = window.getRootContainer().getComponent('Report Viewer')

declare “data” as the bytes for PDF of the report

data = report.getBytesPDF()

declare “path” to be where the writefile ‘path’ will be

path = "C:\Documents and Settings\elec\Desktop\Energy " + window.getRootContainer().getdate + ".pdf"
if path != None:
	system.file.writeFile(path,data)

as long as ‘path’ has a value do a writefile

system.nav.closeWindow('AP7_Power_Reports/Biscuit_Report')

lastly close the window with the report on it

#system.util.invokeLater(test,1000)[/code]

Can anyone please explain how I am using the invokelater function incorrectly. :smiley:

Your invokeLater usage looks fine to me. Its got to be somewhere else.

  1. The backslashes in your filepath need to be escaped - each backslash should become two backslashes.

  2. Use the [tt]print[/tt] command and the console to see where the script is getting to.

The error went when I put “import system” outside of the def (as well as in). I still cannot get to grips with the function invokeLater. I am working with reference to an old forum topic entitled “Automated Reports”. I tried using invokeLater with a simple button that calls a script that makes a messagebox appear. The box appears immediately, I close it, after the delay for the invokeLater it re-appears. Using the example in “Automated Reports” I would expect the report page to be visible for the duration of the invokeLater but this is not the case, my report still appears as a PDF instantly. Should I be concerned about this i.e do I actually need the invokeLater.

It seems someone else had a similar problem in “Reporting module - specific scripting functions?”. They cured it by filtering ??? Getting somewhere I suppose? :scratch:

I can understand the confusion. There are really 2 separate reasons to use an invokeLater here, and I think you should be using two of them.

  1. This code typically runs in a background thread. You need to use the invokeLater to get you out of the background thread and into the GUI thread to manipulate windows.
  2. You want to have an additional delay between opening the window and grabbing the PDF bytes to ensure that bindings have a chance to fire/return and the PDF gets generated.

I think the basic formula should be like this for a client timer script that needs to do an automated report.

[code]condition = check condition for running report
if condition:
def openReportWindow():
open the window

  def printReport():
     get the window
     get the report
     print the report

  # print after 5 second delay *after* opening window
  system.util.invokeLater(printReport, 5000)

opens the report window off the background thread

system.util.invokeLater(openReportWindow)[/code]

Shameless Disclaimer: We are aware that this pattern is full of utter nonsense subtleties that confuse the hell out of a normal user. We have plans for a reporting module v2 later this year that will make this much easier.

At last! This now acts as I expected it to. Report window opens, x seconds later PDF appears and window closes. Thanks for great tech support. I do hope newer versions include more “pre-canned” options as this seems to be very indepth programming ( I am a NooB though). :thumb_left: