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