Build the Display_data Frame

Purpose of the Display_data Frame

The Display_data frame enables users to select and display a SAS table as columnar data. The frame also enables users to subset the displayed data by column, and by using a WHERE expression.
Finished Display_data Frame
Finished Display_data Frame

Create the Display_data Frame

Create the Display_data frame by entering the following command at the SAS command line:
build sasuser.example.Display_data.frame
The SAS command line is usually in the upper-left corner of the main SAS window.
SAS Command Line
SAS Command Line
The empty frame appears and the Components window is displayed.

Build the User Interface for the Display_data Frame

To create the graphical user interface for the frame, drag the following controls from the Components window onto the frame and position them as you see in Preliminary Display_data Frame:
  • one Text Label Control (this is for the title at the top of the frame)
  • three List Box Controls
  • one Table Viewer Control
  • three Push Button Controls
Alternatively, you can select each type of control and then double-click on the frame where you want to place it.
On some UNIX platforms, you might need to press two buttons on your mouse to activate a drag action (consult your host documentation).
If you run out of room while dropping controls on the frame, make the frame bigger by resizing it the way you would resize any other window. You can make it smaller later, after positioning the controls.
After dragging all the controls to the frame, you should now have a frame that resembles the following:
Preliminary Display_data Frame
Preliminary Display_data frame
If you accidentally drop one control inside another so that the larger control completely surrounds the smaller, you might not be able to select the smaller control. To access the smaller control, select the larger control and move it out of the way so that you can select and move the smaller control to its proper position.

Move and Resize the Controls

After you place the controls on the frame, position them like the controls in Finished Display_data Frame by clicking on a control and then placing the mouse pointer on a portion of the light gray border around the control. When the pointer changes into a hand, you can drag the control to a new position.
At this point, the only control that you need to resize is the Table Viewer. To resize a control, select the control and then place the mouse pointer on the dark handles around the control. When the pointer changes into an arrow, you can resize the control.
Mouse Pointers for Moving and Resizing Controls
Mouse Pointers for Moving and Resizing Controls
You can also resize controls with pixel-level accuracy using attributes. Resizing controls using attributes is as simple as entering height and width values. Using attributes to size controls is examined later in this document (see Set the Attributes That Control the Interface).
The remaining controls will be resized using attributes later in this example.

Align the Controls

Although you might have aligned the controls by hand already, there are layout tools available that can help you do the job precisely.
To align the left edges of the three List Box controls, select all three controls by either holding the SHIFT key and clicking each List Box, or by using the mouse to draw a box around all three (controls are selected when their borders turn thick and gray). Now select Layoutthen selectAlignthen selectLefts.
You can drag controls that are selected as a group.
Align the remainder of the components so that your frame resembles Finished Display_data Frame.

Set the Attribute Values for the Display_data Controls

How to Set Attributes

To change the appearance and the behavior of the controls at build time, you must set their attributes by using the Properties window. The procedure for setting attributes at build time is the same for all attributes.

Set the First Attribute

The first attribute to set is the text of the banner at the top of the frame (which currently says Label). To set the Textlabel1 label attribute, follow these steps:
  1. Open the Properties window by right-clicking in the frame and selecting Properties. Notice in the Properties window that all the components are listed on the left.
  2. Select Textlabel1 on the left side of the Properties window.
    The attributes for the Textlabel1 control are listed on the right.
  3. Scroll up the list of attributes until you see the label attribute.
  4. Click inside the Value column on the label row.
  5. Type Sales Data and press ENTER.
    Notice in the frame that the Textlabel1 control now displays Sales Data.
The Properties Window While Setting the Textlabel1 label Attribute
The Properties window while setting the Textlabel1 label attribute
To set the font of the label, follow these steps:
  1. Scroll to the font attribute.
  2. Click inside the Value column where it says (list).
  3. Click on the ellipsis button.
    The Font dialog box appears.
  4. Change the font to Arial, Regular, 16.
  5. Click OK.
In the frame, resize Textlabel1 to make it display the text correctly.

Set the Control Names

Because remembering the generic name for each control might be difficult (Listbox2 does not have much meaning), you should rename the controls. Recall that the names of controls are used as section labels in frame SCL code (which will be added later).
In the Properties window, set the name attribute of each control as follows:
  • Listbox1 to LibrariesListbox
  • Listbox2 to TablesListbox
  • Listbox3 to ColumnsListbox
  • Pushbutton1 to SubsetButton
  • Pushbutton2 to ClearButton
  • Pushbutton3 to CloseButton

Set the Attributes That Control the Interface

To set the text that a user sees in the interface, set the following:
  • LibrariesListbox title attribute to Select library:
  • TablesListbox title attribute to Select table:
  • ColumnsListbox title attribute to Select columns:
  • ClearButton label attribute to Clear Subset
On the SubsetButton, set the following to add text and an icon:
  • buttonStyle attribute to Icon with Text Under
  • icon attribute to 715
  • height attribute to 40
  • label attribute to Subset with WHERE
Although you might want to set the width of the SubsetButton at this point, wait until the next section.
To customize the CloseButton, set the following:
  • commandOnClick attribute to end;
    Note the semicolon at the end of the command.
  • height attribute to 30
  • label attribute to Close Window
  • width attribute to 80
So that users can select more than one item from the ColumnsListbox, set its selectionMode attribute to Multiple Selections.

Set Attribute Values for Multiple Controls

Attributes that are common between two or more controls can be set simultaneously, which can save time. To set the width of the three List Boxes and the SubsetButton, select all three list boxes and the SubsetButton. To select multiple controls on a frame, either hold down the SHIFT key while you click each control, or drag the mouse pointer across each control.
When all four of the components are selected, the Properties window displays only the attributes that the components have in common. Set the width of all four components to 107.
Displaying Shared Attributes
Displaying Shared Attributes
Notice on the frame that all four components have changed widths.
You might need to move or align the controls so that they do not overlap.

Attach Models to the Display_data Frame Controls

Notice that the List Boxes all display a generic list of four items. This is because they, and the Table Viewer on the right side of the frame, have no access to data. To provide all the controls with data, you need to associate them with models. Dropping a model onto a control sets the model attribute on the control, which is all you need to do to associate a control and a model.
To associate the correct model with the proper control, drag the indicated model onto the control on the frame:
  • a Library List Model onto the List Box labeled Select Library (LibrariesListbox)
  • a Data Set List Model onto the List Box labeled Select Table (TablesListbox)
  • a Variable List Model onto the List Box labeled Select Columns (ColumnsListbox)
  • a SAS Data Set Model onto the Table Viewer (Tableviewer1)
You should now see a list of libraries in the LibrariesListbox. By default the Library List model references the currently defined SAS libraries, even at build time. This is why the first List Box displays the current libraries. The other controls don't display any data because, although they are associated with models, those models have not been told where to look for data. You add SCL code to define those data sources in the next section.
Display_data Frame after Attaching Models and Setting Attributes
Display_data Frame after Models Attached and Attributes Set

Add SCL Code to the Display_data Frame

To add the SCL code, making the frame fully functional, open the frame SCL for the Display_data frame (right-click anywhere in the frame and select Frame SCL). Insert the following code:
/* This is the frame SCL for the Display_data frame.       */
/*                                                         */
/* The user selects a library from the LibrariesListbox.   */
/* The TablesListbox is then populated.                    */
/* The user selects a table from the TablesListbox.        */
/* The ColumnsListbox and Tableviewer1 are then populated. */

dcl num rc;   /* Numerical variable used as a return code. */
dcl char(30) displayTable;   /* A character variable.  */
dcl list emptyList={};       /* Creates an empty list. */
    
/* Executes before the frame is displayed to the user. */
Init:
    /* Disable the SubsetButton and the ClearSubset buttons  */
    /* by setting the 'enabled' attribute on each.           */
    /* There is nothing yet to subset or clear.              */
    subsetButton.enabled='no'; 
    clearButton.enabled='no';  

    /*Set how the table is displayed in TablesListBox. */
    datasetlist1.levelCount=1;
return;

/*Executes when a selection is made from the LibrariesListbox. */
LibrariesListbox:
   if LibrariesListbox.selectedItem ne ' ' then
   do;
      /* Set the Data Set List model to point to the library selected. */
      /* Because the Data Set List model is associated with the        */
      /* TablesListbox, the TablesListbox is populated.                */
      datasetList1.library=librariesListbox.selectedItem;
      variableList1.dataSet=' ';
      sasdataset1.table=' ';

      /* Enable the SubsetButton now that there is data to subset. */
      subsetButton.enabled='yes';
   end;
 return;

/* Executes when a selection is made from the TablesListbox. */
TablesListbox:
   if TablesListbox.selectedItem ne ' ' then
   do;
      /* Concatenate the selected library and the selected table */
      /* and give the result to the sasdataset model, the model  */
      /* supplying the Table Viewer with data.                   */
      displayTable=librariesListbox.selectedItem || '.' ||
                   TablesListbox.selectedItem;
      sasdataset1.table=displayTable;
      variableList1.dataSet=displayTable;
      SubsetButton.enabled='yes';
   end;
 return;

/* Executes when a selection is made from the ColumnsListbox. */
ColumnsListbox:
   if listlen(columnsListbox.selectedItems) gt 0 then
      /* Copy the list of selected columns to the sasdataset1 model, */ 
      /* the model supplying the Table Viewer with data.            */
      sasdataset1.columnOrder=copylist(ColumnsListbox.selectedItems);
 return;

/* Executes when the 'Subset with WHERE' button is pressed. */
SubsetButton:
   if sasdataset1.table ne ' ' then
      /* Call the WHERE subset window. */
      rc = sasdataset1._setWhere(0, 'y');

      /* If a WHERE expression is in effect, enable the 'Clear Subset' button. */
      if rc=0 then ClearButton.enabled ='yes';
 return;

/* Executes when the 'Clear Subset' button is pressed. */
ClearButton:
      if sasdataset1.table ne ' ' then
          sasdataset1._setWhere(emptyList); /* Clear the WHERE expression. */
          ClearButton.enabled ='no'; /* Disable the 'Clear Subset' button. */
return;

term:
    /* Delete the list when quitting. */
    rc=dellist(emptyList);
return;
Save the code by selecting Filethen selectSave, and then close the frame SCL window.
Because the frame entry was already named Display_data.frame, the SCL entry that is associated with the frame is automatically named Display_data.scl. If you change the name of the frame later, the frame assumes that the frame SCL name was also changed, so you must either change the name of the SCL entry to match the frame, or edit the frame's SCLEntry attribute to reference the original SCL entry.

Compile the Display_data Frame

With the graphical user interface and the SCL finished, you can now compile the Display_data frame. To compile the frame, make sure it is the active window, and then select Buildthen selectCompile.
If the frame and frame SCL compiled successfully, you should see in the Log window a message similar to the following:
NOTE: Compiling DISPLAY_DATA.FRAME (SASUSER.EXAMPLE.DISPLAY_DATA.SCL).
NOTE: Code generated for DISPLAY_DATA.FRAME. Code size=4095.
To view the Log window, select Viewthen selectLog.
You should correct all errors and warnings before testing the frame (see Compiling Applications).

Testing

Test the Display_data Frame

To test the Display_data frame, make sure it is the active window, and then select Buildthen selectTest.
After the running frame appears, test it by selecting a library, and then a table. For example, select the Sashelp library and the CLASS table. The table data should appear in the Table Viewer.
The Completed Display_data Frame
The Completed Display_data Frame

Test the WHERE Subsetting

Test the subset capabilities by clicking the Subset with WHERE button. The WHERE Expression builder appears.
The WHERE Expression Builder Window
The WHERE Expression Builder Window
Assuming you're viewing the SASHELP.CLASS table, follow these steps to build a simple WHERE expression to display only the females in the SASHELP.CLASS table:
  1. Click Sex in the Available Columns list.
  2. From the operators list, select EQ.
  3. Click <LOOKUP distinct values> in the Available Columns list.
  4. Select F.
  5. Click OK.
The CLASS data is displayed with only the rows that contain SEX='F'.
Results of WHERE SEX='F' Subset
Results of WHERE SEX='F' Subset
Clear the WHERE subsetting by clicking the Clear Subset button.
Close the frame by clicking the Close Window button.

Removing the Frame Command Line

You might have noticed the command prompt at the top of the frame (Command ===>). By default all frames have a command line where users can type SAS commands. To remove the command line at the top of a frame, set the bannerType attribute on the frame to None. The frame is listed in the Properties window as _FRAME_.
After setting the bannerType attribute, recompile, and then test the frame again. Close all Display_data frames when you are finished testing.