Example: Spreadsheet Control

This example uses an ActiveX control that displays a spreadsheet interface. The control, contained in the file msowc.dll, is installed along with a typical installation of Microsoft Office. If the control is not present on your system (you'll know the control is not present if the example code fails when trying to realize the widget hierarchy), the example will not run.

The spreadsheet control has the program ID:

OWC.Spreadsheet.9 

and the class ID:

{0002E510-0000-0000-C000-000000000046} 
 

Note
The spreadsheet control used in this example is included with older versions of Microsoft Office; it is discussed in Microsoft Knowledge Base Article 248822. Newer versions of Microsoft Office may include spreadsheet controls with updated program and class IDs.

Information about the spreadsheet control's properties and methods was gleaned from Microsoft Excel 97 Visual Basic Step by Step by Reed Jacobson (Microsoft Press, 1997) and by inspection of the control's interface using the OLE/COM Object Viewer application provided by Microsoft. It is beyond the scope of this manual to describe the spreadsheet control's interface in detail.

Example Code
This example, ActiveXExcel.pro, is included in the examples\doc\bridges\COM subdirectory of the IDL distribution and develops an IDL routine called ActiveXExcel that illustrates use of the spreadsheet ActiveX control within an IDL widget hierarchy. Run the example procedure by entering ActiveXExcel at the IDL command prompt or view the file in an IDL Editor window by entering .EDIT ActiveXExcel.pro.

  1. Create a function that will retrieve data from cells selected in the spreadsheet control. The function takes two arguments: an object reference to the IDLcomActiveX object that instantiates the spreadsheet control, and a variable to contain the data from the selected cells.
  2. FUNCTION excel_getSelection, oExcel, aData 
    
  3. Retrieve an object that represents the selected cells. Note that when the ActiveX control returns this object, IDL automatically creates an IDLcomActiveX object that makes it accessible within IDL.
  4.    oExcel->GetProperty, SELECTION=oSel 
    
  5. Retrieve the total number of cells selected.
  6.    oSel->GetProperty, COUNT=nCells 
    
  7. If no cells are selected, destroy the selection object and return zero (the failure code).
  8.    IF (nCells LT 1) THEN BEGIN 
          OBJ_DESTROY, oSel 
          RETURN, 0 
       ENDIF 
    
  9. Retrieve objects that represent the dimensions of the selection.
  10.    oSel->GetProperty, COLUMNS=oCols, ROWS=oRows 
    
  11. Get the dimensions of the selection, then destroy the column and row objects.
  12.    oCols->GetProperty, COUNT=nCols 
       OBJ_DESTROY, oCols 
       oRows->GetProperty, COUNT=nRows 
       OBJ_DESTROY, oRows 
    
  13. Create a floating point array with the same dimensions as the selection.
  14.    aData = FLTARR(nCols, nRows, /NOZERO); 
    
  15. Iterate through the cells, doing the following:
    • Retrieve an object that represents the cell. Note that the numeric index of the FOR loop is passed to the GetProperty method as an argument.
    • Get the value contained in the cell.
    • Set the appropriate element of the aData array to the cell's value.
    • Destroy the object.
    •    FOR i=1, nCells DO BEGIN 
            oSel->GetProperty, ITEM=oItem, i 
            oItem->GetProperty, VALUE=vValue 
            aData[i-1] = vValue 
            OBJ_DESTROY, oItem 
         ENDFOR 
      
  16. Destroy the selection object.
  17.    OBJ_DESTROY, oSel 
    
  18. Return one (the success code) and end the function definition.
  19.    RETURN, 1 
     
    END 
    
  20. Next, create a procedure that sets the values of the cells in the spreadsheet. This procedure takes one argument: an object reference to the IDLcomActiveX object that instantiates the spreadsheet control.
  21. PRO excel_setData, oExcel 
    
  22. Define the size of the data array.
  23.    nX = 20 
    
  24. Get an object representing the active spreadsheet.
  25.    oExcel->GetProperty, ActiveSheet=oSheet 
    
  26. Get an object representing the cells in the spreadsheet.
  27.    oSheet->GetProperty, CELLS=oCells 
    
  28. Generate some data.
  29.    im = BESELJ(DIST(nX)) 
    
  30. Iterate through the elements of the data array, doing the following:
    • Retrieve an object that represents the cell that corresponds to the data element. Note that the numeric indices of the FOR loops are passed to the GetProperty method as arguments.
    • Set the value of the cell.
    • Destroy the object.
    •    FOR i=0, nX-1 DO BEGIN 
            FOR j=0, nX-1 DO BEGIN 
               oCells->GetProperty, ITEM=oItem, i+1, j+1 
               oItem->SetProperty, VALUE=im(i,j) 
               OBJ_DESTROY, oItem 
            ENDFOR 
         ENDFOR 
      
  31. Destroy the spreadsheet and cell objects, and end the procedure.
  32.    OBJ_DESTROY, oSheet 
       OBJ_DESTROY, oCells 
     
    END 
    
  33. Next, create a procedure to handle events generated by the widget application.
  34. PRO ActiveXExcel_event, ev 
    
  35. The user value of the top-level base widget is set equal to a structure that contains the widget ID of the ActiveX widget. Retrieve the structure into the variable sState.
  36.    WIDGET_CONTROL, ev.TOP, GET_UVALUE=sState, /NO_COPY 
    
  37. Use the value of the DISPID field of the event structure to sort out "selection changing" events.
  38.   IF (ev.DISPID EQ 1513) THEN BEGIN 
    
  39. Place data from selected cells in variable aData, using the excel_getSelection function defined above. Check to make sure that the function returns a success value (one) before proceeding.
  40.     IF (excel_getSelection(sState.oExcel, aData) NE 0) THEN BEGIN 
    
  41. Get the dimensions of the aData variable.
  42.        szData = SIZE(aData) 
    
  43. If aData is two-dimensional, display a surface, otherwise, plot the data.
  44.        IF (szData[0] GT 1 AND szData[1] GT 1 AND szData[2] GT 1) $ 
             THEN SURFACE, aData $ 
           ELSE $ 
             PLOT, aData 
        ENDIF 
     
      ENDIF 
     
    
  45. Reset the state variable sState and end the procedure.
  46.   WIDGET_CONTROL, ev.TOP, SET_UVALUE=sState, /NO_COPY 
     
    END 
    
  47. Create the main widget creation routine.
  48. PRO ActiveXExcel 
     
       !EXCEPT=0  ; Ignore floating-point underflow errors. 
    
  49. Create a top-level base widget.
  50.    wBase = WIDGET_BASE(COLUMN=1, $ 
          TITLE="IDL ActiveX Spreadsheet Example") 
    
  51. Instantiate the ActiveX spreadsheet control in a widget.
  52.    wAx=WIDGET_ACTIVEX(wBase, $ 
          '{0002E510-0000-0000-C000-000000000046}', $ 
          SCR_XSIZE=600, SCR_YSIZE=400) 
    
  53. Realize the widget hierarchy.
  54.    WIDGET_CONTROL, wBase, /REALIZE 
    
  55. The value of an ActiveX widget is an object reference to the IDLcomActiveX object that encapsulates the ActiveX control. Retrieve the object reference in the variable oExcel.
  56.    WIDGET_CONTROL, wAx, GET_VALUE=oExcel 
    
  57. Turn off the TitleBar property on the spreadsheet control.
  58.    oExcel->SetProperty, DisplayTitleBar=0 
    
  59. Populate the spreadsheet control with data, using the excel_setData function defined above.
  60.    excel_setData, oExcel 
    
  61. Set the user value of the top-level base widget to an anonymous structure that contains the widget ID of the spreadsheet ActiveX widget.
  62.    WIDGET_CONTROL, wBase, SET_UVALUE={oExcel:oExcel} 
    
  63. Call XMANAGER to manage the widgets, and end the procedure.
  64.    XMANAGER,'ActiveXExcel', wBase, /NO_BLOCK 
    END 
    

Running the ActiveXExcel procedure display widgets that look like the following:

Figure 4-2: An IDL Widget Program Using an ActiveX Spreadsheet Control

ActiveXExcel.gif