Messaging

This topic describes progress notification, or messaging, in the ENVI API. See the following sections:

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:

  1. Copy the following code and paste it into a new file named ConsoleMonitorExample__Define.pro. Save the file in the custom_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.
  2. ;-------------------------------------

    ; 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

  3. 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 the custom_code folder of the ENVI installation path.
  4. 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

  5. Copy the following code into the IDL command line to run the example:
  6. e = ENVI(/HEADLESS)

    oConsoleMonitor = ConsoleMonitorExample()

    broadcastSubscribeExample_Broadcaster