Messaging
This topic describes progress notification, or messaging, in the ENVI API. See the following sections:
- Background
- Example: Check if an Abort was Requested
- Custom Tasks with Messaging
- Example: Subscribe to Messages
Background
ENVI uses a broadcast channel to manage messages in the API. Anyone can subscribe to the broadcast channel to listen for specific messages, or to broadcast a message that will transmit to all of the subscribers. The subscribers can decide whether or not to act on a message they receive.
The ENVI user interface subscribes to the broadcast channel and listens for the following messages:
It only acts on these messages if the first one sent is ENVIStartMessage, in which case it displays a progress dialog showing the status of data processing. The ENVI user interface must be initialized. As it receives messages about processing status, it updates the progress dialog accordingly. It dismisses the progress dialog once it receives an ENVIFinishMessage. The user interface ignores any other messages that are sent to the broadcast channel.
To allow end users to cancel (abort) processes, the code should include an ENVIAbortable object. This adds a Cancel button to the progress bar that displays during a running process. If the user clicks the Cancel button, the ABORT_REQUESTED property of ENVIAbortable is set to 1 (true). The code that sent the ENVIStartMessage checks the status of the ABORT_REQUESTED property. When it sees that the property is set to 1, it dismisses the progress dialog.
Example: Check if an Abort was Requested
The following code example sends a start message to the ENVI broadcast channel, performs 73 arbitrary "steps", and checks for messages that the end user cancelled the process. Copy this code into a new window in the IDL Editor, then save it to a file named ProgressBarAbortExample.pro
. Compile and run the program. If you click the Cancel button in the progress dialog, note the number of steps that complete.
This example demonstrates how all of the ENVI API messaging components work together. It simulates an analytic operation and updates its progress in a progress bar and in the IDL console.
PRO ProgressBarAbortExample
COMPILE_OPT idl2
; Start the application
e = ENVI()
; Get the broadcast channel to send messages to the ENVI system
Channel = e.GetBroadcastChannel()
; Create an object that uniquely identifies the message.
; Use the ENVIAbortable object to check if progress
; was cancelled.
Abort = ENVIAbortable()
; Broadcast a start message to the ENVI system
Start = ENVIStartMessage('Progress Bar Title', Abort)
Channel.Broadcast, Start
; Determine the number of steps to calculate
; percent complete for progress
nSteps = 73
; Initialize progress
Progress = ENVIProgressMessage('Executing Progress Message', $
0, Abort)
; Iterate through the work
FOR stepIndex=0, nSteps DO BEGIN
; Calculate progress for the step
percentProgress = Round(stepIndex* 100.0/nSteps)
; Update progress percentage and broadcast the progress
; message to the ENVI system
Progress.Percent = percentProgress
Channel.Broadcast, Progress
; Check if aborted after sending progress to see if
; Abort_Requested was set by any listeners
IF (Abort.Abort_Requested) THEN BREAK
; Simulate an analytic
dataProcess = dist(1000)
; Print the step to see the abort working
PRINT, stepIndex
ENDFOR
; Broadcast a finish message to the ENVI system
Finish = ENVIFinishMessage(Abort)
Channel.Broadcast, Finish
END
Custom Tasks with Messaging
If you are writing a custom task and want to include a progress bar with an option to abort the process, reference the ENVIAbortableTaskFromProcedure base class in your task. In the IDL routine that contains the data processing code, set the ABORTABLE keyword to ENVIStartMessage. When ENVITask::Execute is called on the custom task, an ENVIAbortable object is automatically created that sends an abort message to the user interface if the end user clicks the Cancel button on the progress dialog.
If ENVI is running in batch mode, it ignores these messages because the user interface is not initialized. Progress dialogs should not be invoked in a headless environment.
Example: Subscribe to Messages
To write a script that listens to broadcast messages, use the ENVIMessageHandler and ENVIMessageHandler::OnMessage method. When the script runs, it subscribes to the system's broadcast channel. Anything that sends a message using the ENVIBroadcastChannel Broadcast method is automatically sent to the OnMessage method for further action.
The following example uses the OnMessage method to listen for ENVIStartMessage, ENVIProgressMessage, and ENVIFinishMessage. When it receives these messages, it prints updates to the IDL Console. Follow these steps:
- Copy the following code and paste it into a new file named
ConsoleMonitorExample__Define.pro
. Save the file in thecustom_code
folder of your ENVI installation path. If you do not have write permission for this path, see Toolbox Extensions for other options on deploying custom code. - Copy and paste the following code into a new file named
BroadcastSubscribeExample.pro
. This program sends messages for the console monitor to listen. Save the file in thecustom_code
folder of the ENVI installation path. - Copy the following code into the IDL command line to run the example:
;-------------------------------------
; Name:
; ConsoleMonitorExample
;
; Purpose:
; The ConsoleMonitorExample class
; represents an interface for messages.
;--------------------------------------
FUNCTION ConsoleMonitorExample::Init
COMPILE_OPT IDL2, hidden
IF (~self.ENVIMessageHandler::Init()) THEN BEGIN
RETURN, 0
ENDIF
e = ENVI(/CURRENT)
oChannel = e.GetBroadcastChannel()
oChannel.Subscribe, self
RETURN, 1
END
PRO ConsoleMonitorExample::Cleanup
COMPILE_OPT IDL2, hidden
self.ENVIMessageHandler::Cleanup
e = ENVI(/CURRENT)
oChannel = e.GetBroadcastChannel()
IF (Obj_Valid(oChannel)) THEN BEGIN
oChannel.Unsubscribe, self
ENDIF
END
PRO ConsoleMonitorExample::OnMessage, oMsg
COMPILE_OPT IDL2, hidden
CASE (1) OF
Isa(oMsg,'ENVISTARTMESSAGE'): BEGIN
PRINT, 'Start ', oMsg.message
END
Isa(oMsg,'ENVIPROGRESSMESSAGE'): BEGIN
PRINT, ' ', 'Percent Complete:', oMsg.percent, '%'
END
Isa(oMsg,'ENVIFINISHMESSAGE'): BEGIN
PRINT, 'Finish'
END
ELSE: BEGIN
RETURN
END
ENDCASE
END
PRO ConsoleMonitorExample__define
COMPILE_OPT IDL2
!NULL = {ConsoleMonitorExample, $
inherits ENVIMessageHandler}
END
PRO broadcastSubscribeExample_Broadcaster
COMPILE_OPT IDL2
e = ENVI(/CURRENT)
; Retrieve the broadcast channel to broadcast
; messages to the ENVI system
oChannel = e.GetBroadcastChannel()
; Create an object that uniquely identifies the message
oAbort = ENVIAbortable()
; Broadcast a start message to the ENVI system
oStart = ENVIStartMessage('MyTask', oAbort)
oChannel.Broadcast, oStart
;Determine the number of steps to caculate
; percent complete for progress
nSteps = 10
oProgress = ENVIProgressMessage('Executing Progress Message', $
0, oAbort)
oChannel.Broadcast, oProgress
; Iterate through the work
FOR stepIndex=0, nSteps DO BEGIN
; Calculate progress for the step
percentProgress = stepIndex* 100.0/nSteps
; Broadcast progress message to the ENVI system
oProgress.Percent = percentProgress
oChannel.Broadcast, oProgress
; Check if aborted after sending progress to see if
; Abort_Requested was set
; by any listeners
IF (oAbort.Abort_Requested) THEN BREAK
; Simulate an analytic
dataProcess = dist(1000)
ENDFOR
; Broadcast a finish message to the ENVI system
oFinish = ENVIFinishMessage(oAbort)
oChannel.Broadcast, oFinish
END
e = ENVI(/HEADLESS)
oConsoleMonitor = ConsoleMonitorExample()
broadcastSubscribeExample_Broadcaster