Chapter 27

The Chart and Grid Controls

by Evangelos Petroutsos


CONTENTS

The examples in this chapter demonstrate the Chart and Grid controls. We explored the Chart control in Chapter 9 "More ActiveX Controls," but in this chapter we are going to develop a much more elaborate document that not only graphs data but accepts user-supplied data and then graphs it. The examples of this chapter are complete, functional applications that can run from within Internet Explorer (and soon from within other browsers, too). They demonstrate the kind of functionality you can add to your Web pages with VBScript and ActiveX controls.

The first application relies on ActiveX controls and can be safely posted on the Web. The Chart application, shown in Figure 27.1, is a data-graphing application that lets the user enter data in the TextBox controls at the layout's lower-right corner. Each time the user changes a value in one of the values, the graph is updated automatically. The group of TextBox controls used for data entry was arranged as a spreadsheet, but since each cell requires its own TextBox control and the corresponding code, we couldn't place too many cells on the layout with this approach. We are going to eliminate this limitation later with the Grid control.
Figure 27.1 : The Chart application graph's user-supplied data at runtime.

For a real data-entry and graphing application, you need a Grid control. A Grid control is an old OLE control, which will already be installed on your system if you have Visual Basic or Visual C++. It's a miniature spreadsheet, with most of the functionality you need to implement a data-entry and graphing application, like the one shown in Figure 27.2. This example is called GridChart, and you'll see how it was implemented in the second half of this chapter. The code is more compact than the code of the Grid application, because we don't have to repeat identical subroutines for each cell and we can provide as many cells as necessary for the user to enter data.

Figure 27.2 : The GridChart application provides a Grid control, where the user can enter the data to be graphed.

The drawback of the GridChart application is that it can only be used locally or in an intranet environment, because it makes use of an old OLE control that does not come with Internet Explorer, and many users might not have it. We are assuming that you have Visual Basic installed on your system and you have access to this control. Besides, it won't be long before an ActiveX version of the Grid control becomes available. (Keep an eye on Microsoft's Workshop site, at www.microsoft.com/workshop.)

There's one more reason why the two controls are combined in the GridChart example. The data graphed by the Graph control is stored into the control in a two-dimensional array. The rows of the array correspond to different datasets and its columns to the individual points in each dataset. The structure of the Grid control is quite similar. The Grid control is a tabular arrangement of cells. The GridChart application maps the rows of the grid to datasets of the Chart control. The similarities between the two controls are not limited to the surface. The methods for accessing data points in the Chart control and cells in the Grid control are quite similar. In essence, you must first set the row and column index of the element you want to access. These two values uniquely identify an element (a cell in the Grid control and a data point in the Chart control). Then, you can access the element (read or set its value) with the Text property of the Grid control, or the DataItem of the Chart control. The remaining properties of both controls determine the appearance of the control (the appearance of the graph or the placement and look of the data in the grid's cells). They have intuitive names, and you can easily figure out their purpose. Even if you don't, you can look up the help files and experiment with their settings to get what you want. The important thing is to understand the basic mechanism for accessing the elements of these two controls, and you'll be able to use them very efficiently.

The Chart Example

The Chart application is a demonstration of the various properties of the Chart control. It also shows how to change the control's data at runtime, by plugging new values into the control's data array. The user interface of the application consists of a Chart control, a number of OptionButton and CheckBox controls that control the graph's appearance, and a number of TextBox controls where the user may change the data values.

The OptionButton controls that control the appearance of the graph are by far less than the actual graph types, but when combined, they can specify all graph types. The settings of the GraphType property let you specify only eight different charts (Pie, Point, Line, Area, Column, Bar, HLC, OHLC chart), but each one comes in three flavors: simple, stacked, and full (100%). The Chart application lets you select separately the type of the graph and its variation, thus eliminating the need for 20 different Option buttons.

The Chart application was implemented as an HTML document. There are no layouts on the page of Figure 27.1. The various controls were aligned with an elaborate table structure, which you may ignore if you are not familiar with HTML. Placing the controls on a layout is actually simpler. The code of the application is shown in Listing 27.1.


Listing 27.1. The Chart project's complete code.

  1: 

  2: <HTML>

  3: <HEAD>

  4: <TITLE>Chart Control Demo</TITLE>

  5: <SCRIPT LANGUAGE="VBS">

  6:     Sub DoChartType(CType)

  7:     Chart.ChartType=CType

  8:     End Sub

  9:     Sub DoChartStyle(CStyle)

 10:            if Chart.ChartType < 2 then Exit Sub

 11:     currentStyle=Chart.ChartType

 12:     if CStyle = 0 then

 13:         if (currentStyle-2) mod 2 = 0 then Exit Sub

 14:         if (currentStyle-3) mod 2 = 0 then Chart.ChartType=currentStyle - 1

 15:         if (currentStyle-4) mod 2 = 0 then Chart.ChartType=currentStyle - 2

 16:         Exit Sub

 17:     end if

 18:     if CStyle = 1 then

 19:         if (currentStyle-2) mod 2 = 0 then Chart.ChartType=currentStyle + 1

 20:         if (currentStyle-3) mod 2 = 0 then Exit Sub

 21:         if (currentStyle-4) mod 2 = 0 then Chart.ChartType=currentStyle + 1

 22:         Exit Sub

 23:     end if

 24:     if CStyle = 2 then

 25:         if (currentStyle-2) mod 2 = 0 then Chart.ChartType=currentStyle + 2

 26:         if (currentStyle-3) mod 2 = 0 then Chart.ChartType=currentStyle + 1

 27:         if (currentStyle-4) mod 2 = 0 then Exit Sub

 28:         Exit Sub

 29:     End if

 30:     End Sub

 31:     Sub HorizontalGrid(HGrid)

 32:        if HGrid.Checked = 1 then

 33:           Chart.HGridStyle = 1

 34:        else

 35:           Chart.HGridStyle = 0

 36:        end if

 37:     End Sub

 38:     Sub VerticalGrid(VGrid)

 39:        if VGrid.Checked = 1 then

 40:           Chart.VGridStyle = 1

 41:        else

 42:           Chart.VGridStyle = 0

 43:        end if

 44:     End Sub

 45: 

 46:     Sub NewData(row, col, Data)

 47:         Chart.RowIndex = row

 48:         Chart.ColumnIndex = col

 49:         Chart.DataItem =Data.Value

 50:     End Sub

 51: </SCRIPT>

 52: </HEAD>

 53: <BODY>

 54: <H1>Chart Active Control Demo</H1>

 55: This page demonstrates the properties of the Chart Active Control.<BR>

 56: Every time you change the settings of the chart, or any data values, the chart

           is updated automatically.

 57: <P>

 58: <TABLE BORDER>

 59: <TR><TD>

 60: <OBJECT

 61:     classid="clsid:FC25B780-75BE-11CF-8B01-444553540000"

 62:     id=Chart

 63:     width=240

 64:     height=260

 65:         align=center

 66:     hspace=0

 67:     vspace=0>

 68:     <param name="BackColor" value="14737632">

 69:     <param name="ChartStyle" value="0">

 70:     <param name="ChartType" value="4">

 71:     <param name="HGridStyle" value="0">

 72:     <param name="VGridStyle" value="0">

 73:     <param name="ColorScheme" value="0">

 74:     <param name="Rows" value="2">

 75:     <param name="Columns" value="5">

 76:     <param name="data[0][0]" value="15">

 77:     <param name="data[0][1]" value="13">

 78:     <param name="data[0][2]" value="22">

 79:     <param name="data[0][3]" value="17">

 80:     <param name="data[0][4]" value="14">

 81:     <param name="data[1][0]" value="23">

 82:     <param name="data[1][1]" value="18">

 83:     <param name="data[1][2]" value="19">

 84:     <param name="data[1][3]" value="24">

 85:     <param name="data[1][4]" value="21">

 86: 

 87: </OBJECT>

 88: <TD BGCOLOR=#E0E0E0>

 89: <FORM>

 90: <TABLE>

 91: <TR>

 92: <TD COLSPAN=2 BGCOLOR=#FFFFCC>Chart Type</TD>

 93: <TD BGCOLOR=#FFFFCC>Chart Style</TD>

 94: </TR>

 95: <TR>

 96: <TD><INPUT TYPE="RADIO" NAME="TypeGroup" onClick="DoChartType(0)">Pie</TD>

 97: <TD><INPUT TYPE="RADIO" NAME="TypeGroup" onClick="DoChartType(2)">Point</TD>

 98: <TD><INPUT TYPE="RADIO" checked NAME="StyleGroup"

           onClick="DoChartStyle(0)">Simple

 99: </TR>

100: <TR>

101: <TD><INPUT TYPE="RADIO" NAME="TypeGroup" onClick="DoChartType(5)">Line</TD>

102: <TD><INPUT TYPE="RADIO" NAME="TypeGroup" onClick="DoChartType(8)">Area</TD>

103: <TD><INPUT TYPE="RADIO" NAME="StyleGroup" onClick="DoChartStyle(1)">Stacked

104: </TR>

105: <TR>

106: <TD><INPUT TYPE="RADIO" NAME="TypeGroup" CHECKED

           onClick="DoChartType(11)">Column</TD>

107: <TD><INPUT TYPE="RADIO" NAME="TypeGroup" onClick="DoChartType(14)">Bar</TD>

108: <TD><INPUT TYPE="RADIO" NAME="StyleGroup"

           onClick="DoChartStyle(2)">100%</TD></TD>

109: </TR>

110: <TR>

111: <TD COLSPAN=3 BGCOLOR=#FFFFCC>Grid</TD>

112: </TR>

113: <TR>

114: <TD><INPUT TYPE="CHECKBOX" NAME="HGrid"

           onClick="HorizontalGrid(HGrid)">Horizontal</TD>

115: <TD><INPUT TYPE="CHECKBOX" NAME="VGrid"

           onClick="VerticalGrid(VGrid)">Vertical</TD>

116: <TD></TD>

117: <TR>

118: <TD COLSPAN=3 BGCOLOR=#FFFFCC>Stock Prices</TD>

119: <TR>

120: <TD COLSPAN=3>

121: <TABLE>

122: <TD></TD>

123: <TD><INPUT TYPE="BUTTON" VALUE="MSOFT"></TD>

124: <TD><INPUT TYPE="BUTTON" VALUE="IBM"></TD>

125: <TD><INPUT TYPE="BUTTON" VALUE="DEC"></TD>

126: <TD><INPUT TYPE="BUTtON" VALUE="NETSCAPE"></TD>

127: <TD><INPUT TYPE="BUTTON" VALUE="NOVEL"></TD>

128: <TR>

129: <TD><INPUT TYPE="Button" VALUE="This week"></TD>

130: <TD><INPUT TYPE="Text" NAME="d00" SIZE=11 VALUE="15"

           onChange="NewData 0, 0, d00"></TD>

131: <TD><INPUT TYPE="Text" NAME="d01" SIZE=11 VALUE="13"

           onChange="NewData 0, 1, d01"></TD>

132: <TD><INPUT TYPE="Text" NAME="d02" SIZE=11 VALUE="22"

           onChange="NewData 0, 2, d02"></TD>

133: <TD><INPUT TYPE="Text" NAME="d03" SIZE=11 VALUE="17"

           onChange="NewData 0, 3, d03"></TD>

134: <TD><INPUT TYPE="Text" NAME="d04" SIZE=11 VALUE="14"

           onChange="NewData 0, 4, d04"></TD>

135: <TR>

136: <TD><INPUT TYPE="Button" VALUE="Last Week"></TD>

137: <TD><INPUT TYPE="Text" NAME="d10" SIZE=11 VALUE="23"

           onChange="NewData 1, 0, d10"></TD>

138: <TD><INPUT TYPE="Text" NAME="d11" SIZE=11 VALUE="18"

           onChange="NewData 1, 1, d11"></TD>

139: <TD><INPUT TYPE="Text" NAME="d12" SIZE=11 VALUE="19"

           onChange="NewData 1, 2, d12"></TD>

140: <TD><INPUT TYPE="Text" NAME="d13" SIZE=11 VALUE="24"

           onChange="NewData 1, 3, d13"></TD>

141: <TD><INPUT TYPE="Text" NAME="d14" SIZE=11 VALUE="21"

           onChange="NewData 1, 4, d14"></TD>

142: </TR>

143: </TABLE>

144: </TD>

145: </TR>

146: </TABLE>

147: </FORM>

148: </TD>

149: </TR>

150: </TABLE>

151: </BODY>

152: </HTML>


Notice that the OptionButton controls contain the onChange attribute in their definitions, which specifies the name of the procedure to be executed every time the user checks, or clears, them. The subroutines DoChartType() and DoChartStyle()do all the work in this program. The DoChartType() subroutine sets the basic type of the graph and the DoStyleChart() subroutine sets the flavor of the basic type. They both accept an argument, which is a number representing the chart's type and style. Both subroutines examine the value of their argument and set the value of the GraphType property accordingly. The DoChartType() subroutine accepts an integer argument, which is the value of the GraphType property for the simple version of the desired type (0 for pie charts, 2 for line plots, 5 for point plots, and so on). The DoChartStyle() subroutine accepts an integer which is 0 for simple charts, 1 for stacked charts, and 2 for full charts.

The same method of invoking the proper subroutine is used when a TextBox's value changes, too. This time we used the onChange attribute, which calls the specified subroutine each time the control's value changes. When the value changes, all TextBox controls call the NewData() subroutine, with three arguments: the dataset and datapoint number and the new value. The dataset number is 0 or 1, depending on the row of the TextBox, and the datapoint number is a value between 0 and 4. (There are five datapoints in each dataset.)

The rest of the code is rather trivial, in the sense that it sets the various properties of the Chart control to adjust the graph's appearance. You might want to examine the DoChartStyle() subroutine, which sets the graph's type based on the arguments it receives when called.

The GridChart Example

The GridChart document we are going to implement in this chapter is shown in Figure 27.1, and you will find it on the CD. It's one of the lengthiest applications presented in this book, and it demonstrates not only a few controls but the type of functionality you add to your VBScript applications with the help of ActiveX controls. As you will soon realize, the code is rather straightforward, once you understand the concepts of manipulating the Grid and Chart controls. Fortunately, there are many similarities between the two controls, and this will simplify the code too.

The GridChart project is similar in principle to the Grid project, except the data-entry aspect of the application has been vastly improved with the functionality of the Grid control. The drawback of this application is that you can't use it unless you have the Grid control installed on your system. (It's an OLE control that comes with Microsoft's languages and can be freely distributed with the application.) Moreover, the user will see a warning every time Internet Explorer loads the control, as discussed in the previous chapters. When the warning appears, click Yes to load the control. As long as you have the source code and can verify that you are loading a Microsoft control, there's no security risk for your computer.

The user interface of the GridChart project is straightforward. The grid is where the user enters data and the various command buttons perform a few basic operations. The Edit Grid button displays a pop-up menu, with the following commands:

Delete current rowDeletes all the cells in the current row.
Delete current columnDeletes all the cells in the current column.
Fill current rowFills all the cells in the current row with a user-supplied value.
Fill current columnFills all the cells in the current column with a user-supplied value.
Clear GridClears the contents of the grid.

These commands are quite easy to implement, and they demonstrate the types of operations you can perform on the Grid control.

The Process Data button leads to another pop-up menu, with the following commands:

MEAN of selected cells
MIN of selected cells
MAX of selected cells

These commands have not been implemented, but you will see how you can detect the selected cells in the grid and access their values shortly. Then you'll be able to implement these, as well as other, more complicated calculations with the selected cells.

The last button, Plot Data, copies the values of the selected cells to the Chart control, which plots them immediately.

The OptionButton and CheckButton controls next to the Chart control control the appearance of the graph. They simply set the GraphType, HGridStyle, and VGridStyle properties of the Grid accordingly-and you'll probably want to add more options to better control your graphs.

The Grid Control

The Grid control is a simple spreadsheet you can place on your layouts to either display or accept data from the user. It looks a lot like a spreadsheet, with cells arranged in a table, and each cell can be addressed via a row and a column number. The Grid control was designed for presenting data to the user and doesn't provide any means for accepting user input. This problem, however, is easily fixed by taking control of the KeyPress events on the control. You can supply some VBScript code in the Grid's KeyPress event to convert the user's keystrokes to digits and display them in the current cell.

Figure 27.3 shows a Grid control as it appears on a layout, in the ActiveX Control Pad. To place a Grid control on a layout, you must first add its icon to the toolbox, with the help of the Additional controls commands of its shortcut menu. In the Insert ActiveX control dialog box, select Grid Object and a little grid icon will be placed on the toolbox. (You can see it in the toolbox of Figure 27.3.) Use this icon to place Grid controls on your layouts just like all other controls.

Figure 27.3 : A Grid control placed on a layout with the ActiveX Control Pad.

The cells of the first row and column have a gray background because they were meant to be used as titles for the corresponding columns and rows. The unique feature of these cells is that they don't scroll along with the rest of the cells, so the titles always remain visible. You can change the number of title rows and columns with the FixedCols and FixedRows properties. Another characteristic of the title row and column is that when one of their cells is clicked, the entire row or column is selected.

Let's start by looking at the Grid control's properties, which we are going to use in the code. The number of visible columns and rows on the control is set by the Rows and Cols properties. Depending on the size of the control and the number and size of the cells, it's possible that not all cells will fit within the control's dimensions. In this case, you can attach a vertical and/or a horizontal scrollbar, to let the user quickly locate the section of the grid he or she wants to view. The scrollbars will not be visible during the design of the project and will appear when the document is opened with Internet Explorer only if they are needed.

Each column in the grid may have its own width, which is controlled by the ColWidth property. To set the width of the first column (the title column), use the statement


Grid1.ColWidth(0)=500

The width's value is expressed in twips, and there are 20 twips in a point. The previous statement sets the width of the first column to approximately 25 points. Likewise, each row may have a different height, which is controlled by the RowHeight property, whose syntax is quite similar. Notice that the user can change the width of columns and height of rows at runtime, by dragging the column and row separators with the mouse. If you place the mouse over a dividing line between two columns (or rows) and in the title section of the grid, it will assume the shape of a double arrow, indicating that it can be dragged to resize a row or column of cells.

To access a specific cell, assign its coordinates to the Row and Col properties of the control and then access its Text property. The Text property can be read or set. As you might recall, the same approach is used with the Chart control to assign values to its Data array, which holds the datapoints to be plotted. As with the Chart control, the indexing of the Grid control's rows and columns starts at 0. To read the value of the fifth cell on the second column, use the statements


Grid1.Row=4

Grid1.Col=1

thisnumber=Grid1.Text

or replace the third statement with one like the following to assign a new value to the cell:

Grid1.Text=100.01

To read all the values in the fourth row and store them in an array, you must use a loop like this one:


Grid1.Row=3

For icol=1 to MaxRows

    Grid1.Col=icol

    a(icol)=Grid1.Text

Next

If you want to read multiple rows and store them in a two-dimensional array, use two nested loops, the outer one scanning the selected rows and the inner one scanning the selected columns in each row. As you might have guessed already, we'll use a similar loop to copy the values of the selected cells on the grid to the chart's data array.

The SelStartRow and SelStartCol properties return the number of the first and last selected rows respectively. Likewise, the SelStartCol and SelEndCol properties return the first and last selected columns in the grid. Because the user will rarely fill in all the cells in a grid, use these four properties to limit the area of the grid you work with. When the user is ready to plot the grid's data, he or she must first select a range of cells with the mouse and then click on the Plot Data button. The program assumes that each dataset corresponds to a row of the grid and the columns are the datapoints. The code that copies the values from the grid to the Chart control's data array is shown here:


StartRow=Grid1.SelStartRow

StartCol=Grid1.SelStartCol

EndRow=Grid1.SelEndRow

EndCol=Grid1.SelEndCol



IEChart1.Columns=EndRow-StartRow+1

IEChart1.Rows=EndCol-StartCol+1



ccol=0

For irow=StartRow to EndRow

    crow=0

    For icol=StartCol to EndCol

        Grid1.Row=irow

        Grid1.Col=icol

        IEChart1.RowIndex=crow

        IEChart1.ColumnIndex=ccol

        IEChart1.DataItem=Grid1.Text

        crow=crow+1

    Next

    ccol=ccol+1

Next

First it sets the StartRow, EndRow, StartCol, and EndCol properties that delimit the area of the grid we are interested in. Then, it sets the Columns and Rows properties of the Chart control so that the correct number of datasets and data points in each dataset will be plotted. The two loops do the actual copying of the values from the Grid to the Chart control. Notice the similarities in the commands that select the current cell in the grid and the current data point in the current dataset in the Chart control. For both controls, we set a column and a row value, which identify a single element (a cell in the case of the Grid control and a data value in the case of the Graph control). Then we use the Text property to read the value of the current cell in the Grid control and the DataItem property of the Chart control to set the value of the current data point in the Graph control. As soon as all the values have been copied, the Chart control's graph will be updated. This code must be placed in the Plot Data Command button's Click event and is probably the most challenging (and most interesting) part of the application. Most of the remaining code simply sets the various properties of the controls.

Implementing the Application

The first problem to deal with is how to make the Grid control accept user data. By default, the Grid control does not let the user enter data. But it recognizes the various Keyboard events, so it shouldn't be difficult to simulate data-entry operations. Indeed, you can place a few lines of VBScript code in the control KeyPress event to capture the keystrokes and translate them to digits to be displayed on the current cell. The code is fairly simple; it has to check the key pressed and make sure that it was a valid alphanumeric symbol and then append it to the current cell's contents. Providing the functionality of the various editing keys, especially mouse operations, is quite complicated, so we decided to let the user edit the cells' contents with the Backspace key only. Here's the code of the Grid's KeyPress event handler:


Sub Grid1_KeyPress(ByVal KeyAscii)

If KeyAscii=8 and Len(Grid1.Text)>0 Then

   Grid1.Text=Left(Grid1.Text, Len(Grid1.Text)-1)

   Exit Sub

End If

If KeyAscii<32 Then

   Exit Sub

End If

Grid1.Text=Grid1.Text+chr(KeyAscii)

End Sub

The first If structure checks for the Backspace key. If the Backspace key was pressed and the cell contains text, it deletes the rightmost character. If the key pressed does not correspond to a printable character, the keystroke is ignored. If you open the GridChart application and test-drive it for a few minutes, you'll realize that this short code works quite well.

The various commands of the Edit pop-up menu are straightforward, too. They make use of the Cols and Rows properties of the Grid control to assign values to a range of cells with a For...Next loop. The subroutine that fills a row with a user-supplied value is


Sub FillRow()

   Entry=InputBox("Please enter value to copy into current row")

   irow=Grid1.Row

   For icol=1 to Grid1.Cols-1

      Grid1.Col=icol

      Grid1.Text=Entry

   Next

End Sub

The code for deleting the contents of the cells in a given row is


Sub DelRow()

   irow=Grid1.Row

   For icol=1 to Grid1.Cols-1

      Grid1.Col=icol

      Grid1.Text=""

   Next

End Sub

We have already examined the code behind the Plot Data button, which copies the values of the selected cells from the Grid to the Chart control. The complete code of the GridChart project is shown in Listing 27.2.


Listing 27.2. The GridChart project's complete code.

  1: <SCRIPT LANGUAGE="VBScript">

  2: <!--

  3: Sub Form_onLoad()

  4:    Grid1.Row=0

  5:    For icol=1 to Grid1.Cols-1

  6:       Grid1.Col=icol

  7:       title="C" & icol

  8:       Grid1.Text=title

  9:    Next

 10:    Grid1.Col=0

 11:    For icol=1 to Grid1.Rows-1

 12:       Grid1.Row=icol

 13:       Grid1.Text="R" & icol

 14:    Next

 15: End Sub

 16: 

 17: Sub CommandButton1_Click()

 18:    call EditMenu.Popup()

 19: End Sub

 20: 

 21: Sub Grid1_KeyPress(ByVal KeyAscii)

 22: If KeyAscii=8 and Len(Grid1.Text)>0 Then

 23:    Grid1.Text=Left(Grid1.Text, Len(Grid1.Text)-1)

 24:    Exit Sub

 25: End If

 26: If KeyAscii<32 Then

 27:    Exit Sub

 28: End If

 29: Grid1.Text=Grid1.Text+chr(KeyAscii)

 30: End Sub

 31: 

 32: Sub DelRow()

 33:    irow=Grid1.Row

 34:    For icol=1 to Grid1.Cols-1

 35:       Grid1.Col=icol

 36:       Grid1.Text=""

 37:    Next

 38: End Sub

 39: 

 40: Sub DelColumn()

 41:    icol=Grid1.Column

 42:    For irow=1 to Grid1.Rows-1

 43:       Grid1.Row=irow

 44:       Grid1.Text=""

 45:    Next

 46: End Sub

 47: 

 48: Sub FillRow()

 49:    Entry=InputBox("Please enter value to copy into current row")

 50:    irow=Grid1.Row

 51:    For icol=1 to Grid1.Cols-1

 52:       Grid1.Col=icol

 53:       Grid1.Text=Entry

 54:    Next

 55: End Sub

 56: 

 57: sub FillColumn()

 58:    Value=InputBox("Please enter value to copy into current column")

 59:    icol=Grid1.Col

 60:    for irow=1 to Grid1.Rows-1

 61:       Grid1.Row=irow

 62:       Grid1.Text=Value

 63:    next

 64: End sub

 65: 

 66: sub ClearGrid()

 67:    for icol=1 to Grid1.Cols

 68:       for irow=1 to Grid1.Rows-1

 69:          Grid1.Row=irow

 70:          Grid1.Col=icol

 71:          Grid1.Text=""

 72:       next

 73:    next

 74: End sub

 75: 

 76: Sub EditMenu_Click(ByVal item)

 77:    if item=1 then DelRow()

 78:    if item=2 then DelColumn()

 79:    if item=3 then FillRow()

 80:    if item=4 then FillColumn()

 81:    if item=5 then ClearGrid()

 82: End Sub

 83: 

 84: Sub Mean()

 85: msgbox "ENTER MEAN CALCULATIONS HERE"

 86: End Sub

 87: 

 88: Sub Max()

 89: msgbox "ENTER MAX CALCULATIONS HERE"

 90: End Sub

 91: 

 92: Sub Min()

 93: msgbox "ENTER MIN CALCULATIONS HERE"

 94: End Sub

 95: 

 96: Sub ProcessMenu_Click(ByVal item)

 97:    if item=1 then Mean()

 98:    if item=2 then Max()

 99:    if item=3 then Min()

100: End Sub

101: 

102: Sub CommandButton2_Click()

103: StartRow=Grid1.SelStartRow

104: StartCol=Grid1.SelStartCol

105: EndRow=Grid1.SelEndRow

106: EndCol=Grid1.SelEndCol

107: 

108: IEChart1.Columns=EndRow-StartRow+1

109: IEChart1.Rows=EndCol-StartCol+1

110: 

111: ccol=0

112: For irow=StartRow to EndRow

113:     crow=0

114:     For icol=StartCol to EndCol

115:         Grid1.Row=irow

116:         Grid1.Col=icol

117:         IEChart1.RowIndex=crow

118:         IEChart1.ColumnIndex=ccol

119:         IEChart1.DataItem=Grid1.Text

120:         crow=crow+1

121:     Next

122:     ccol=ccol+1

123: Next

124: End Sub

125: 

126: Sub CommandButton3_Click()

127: ProcessMenu.PopUp()

128: end Sub

129: 

130: Sub OptionButton1_Change()

131:     IEChart1.ChartType=1

132: End Sub

133: 

134: Sub OptionButton2_Change()

135:     IEChart1.ChartType=5

136: End Sub

137: 

138: Sub OptionButton3_Change()

139:     IEChart1.ChartType=14

140: End Sub

141: 

142: Sub OptionButton4_Change()

143:     IEChart1.ChartType=8

144: End Sub

145: 

146: Sub CheckBox1_Change()

147:     If CheckBox1.Value Then

148:         IEChart1.HGridStyle=1

149:     Else

150:         IEChart1.HGridStyle=0

151:     End If

152: End Sub

153: 

154: Sub CheckBox2_Change()

155:     If CheckBox2.Value Then

156:         IEChart1.VGridStyle=1

157:     Else

158:         IEChart1.VGridStyle=0

159:     End If

160: End Sub

161: 

162: -->

163: </SCRIPT>

164: <DIV STYLE="LAYOUT:FIXED;WIDTH:556pt;HEIGHT:314pt;">

165:     <OBJECT ID="Image1"

166:      CLASSID="CLSID:D4A97620-8E8F-11CF-93CD-00AA00C08FDF"

                      STYLE="TOP:149pt;LEFT:17pt;WIDTH:528pt;HEIGHT:165pt;ZINDEX:0;">

167:         <PARAM NAME="BorderStyle" VALUE="0">

168:         <PARAM NAME="SizeMode" VALUE="3">

169:         <PARAM NAME="SpecialEffect" VALUE="1">

170:         <PARAM NAME="Size" VALUE="18627;5821">

171:         <PARAM NAME="PictureAlignment" VALUE="0">

172:         <PARAM NAME="VariousPropertyBits" VALUE="19">

173:     </OBJECT>

174:     <OBJECT ID="Grid1"

175:      CLASSID="CLSID:A8C3B720-0B5A-101B-B22E-00AA0037B2FC"

                      STYLE="TOP:17pt;LEFT:17pt;WIDTH:429pt;HEIGHT:123pt;ZINDEX:1;">

176:         <PARAM NAME="_Version" VALUE="65536">

177:         <PARAM NAME="_ExtentX" VALUE="15134">

178:         <PARAM NAME="_ExtentY" VALUE="4339">

179:         <PARAM NAME="_StockProps" VALUE="77">

180:         <PARAM NAME="BackColor" VALUE="16777215">

181:         <PARAM NAME="Rows" VALUE="20">

182:         <PARAM NAME="Cols" VALUE="20">

183:     </OBJECT>

184:     <OBJECT ID="CommandButton1"

185:      CLASSID="CLSID:D7053240-CE69-11CD-A777-00DD01143C57"

                      STYLE="TOP:66pt;LEFT:454pt;WIDTH:83pt;HEIGHT:25pt;TABINDEX:1;

                      ZINDEX:2;">

186:         <PARAM NAME="Caption" VALUE="Edit Grid">

187:         <PARAM NAME="Size" VALUE="2911;882">

188:         <PARAM NAME="FontHeight" VALUE="240">

189:         <PARAM NAME="FontCharSet" VALUE="0">

190:         <PARAM NAME="FontPitchAndFamily" VALUE="2">

191:         <PARAM NAME="ParagraphAlign" VALUE="3">

192:         <PARAM NAME="FontWeight" VALUE="0">

193:     </OBJECT>

194:     <OBJECT ID="CommandButton2"

195:      CLASSID="CLSID:D7053240-CE69-11CD-A777-00DD01143C57"

                             STYLE="TOP:116pt;LEFT:454pt;WIDTH:83pt;HEIGHT:25pt;

							 TABINDEX:2;ZINDEX:3;">

196:         <PARAM NAME="Caption" VALUE="Plot Data">

197:         <PARAM NAME="Size" VALUE="2911;882">

198:         <PARAM NAME="FontHeight" VALUE="240">

199:         <PARAM NAME="FontCharSet" VALUE="0">

200:         <PARAM NAME="FontPitchAndFamily" VALUE="2">

201:         <PARAM NAME="ParagraphAlign" VALUE="3">

202:         <PARAM NAME="FontWeight" VALUE="0">

203:     </OBJECT>

204:     <OBJECT ID="CommandButton3"

205:      CLASSID="CLSID:D7053240-CE69-11CD-A777-00DD01143C57"

                      STYLE="TOP:91pt;LEFT:454pt;WIDTH:83pt;HEIGHT:25pt;TABINDEX:3;

                      ZINDEX:4;">

206:         <PARAM NAME="Caption" VALUE="Process Data">

207:         <PARAM NAME="Size" VALUE="2911;882">

208:         <PARAM NAME="FontHeight" VALUE="240">

209:         <PARAM NAME="FontCharSet" VALUE="0">

210:         <PARAM NAME="FontPitchAndFamily" VALUE="2">

211:         <PARAM NAME="ParagraphAlign" VALUE="3">

212:         <PARAM NAME="FontWeight" VALUE="0">

213:     </OBJECT>

214:     <OBJECT ID="iechart1"

215:      CLASSID="CLSID:FC25B780-75BE-11CF-8B01-444553540000"

                      STYLE="TOP:157pt;LEFT:50pt;WIDTH:313pt;HEIGHT:140pt;ZINDEX:5;">

216:         <PARAM NAME="_ExtentX" VALUE="11033">

217:         <PARAM NAME="_ExtentY" VALUE="4948">

218:         <PARAM NAME="Rows" VALUE="4">

219:         <PARAM NAME="Columns" VALUE="3">

220:         <PARAM NAME="ChartType" VALUE="8">

221:         <PARAM NAME="Data[0][0]" VALUE="0">

222:         <PARAM NAME="Data[0][1]" VALUE="10">

223:         <PARAM NAME="Data[0][2]" VALUE="11">

224:         <PARAM NAME="Data[1][0]" VALUE="7">

225:         <PARAM NAME="Data[1][1]" VALUE="11">

226:         <PARAM NAME="Data[1][2]" VALUE="12">

227:         <PARAM NAME="Data[2][0]" VALUE="6">

228:         <PARAM NAME="Data[2][1]" VALUE="12">

229:         <PARAM NAME="Data[2][2]" VALUE="13">

230:         <PARAM NAME="Data[3][0]" VALUE="11">

231:         <PARAM NAME="Data[3][1]" VALUE="13">

232:         <PARAM NAME="Data[3][2]" VALUE="14">

233:         <PARAM NAME="HorizontalAxis" VALUE="0">

234:         <PARAM NAME="VerticalAxis" VALUE="0">

235:         <PARAM NAME="hgridStyle" VALUE="0">

236:         <PARAM NAME="vgridStyle" VALUE="0">

237:         <PARAM NAME="ColorScheme" VALUE="0">

238:         <PARAM NAME="BackStyle" VALUE="1">

239:         <PARAM NAME="Scale" VALUE="100">

240:         <PARAM NAME="DisplayLegend" VALUE="1">

241:         <PARAM NAME="BackColor" VALUE="16777215">

242:         <PARAM NAME="ForeColor" VALUE="32768">

243:     </OBJECT>

244:     <OBJECT ID="OptionButton1"

245:      CLASSID="CLSID:8BD21D50-EC42-11CE-9E0D-00AA006002f3"

                      STYLE="TOP:173pt;LEFT:396pt;WIDTH:108pt;HEIGHT:18pt;TABINDEX:4;

                      ZINDEX:6;">

246:         <PARAM NAME="BackColor" VALUE="2147483663">

247:         <PARAM NAME="ForeColor" VALUE="2147483666">

248:         <PARAM NAME="DisplayStyle" VALUE="5">

249:         <PARAM NAME="Size" VALUE="3810;635">

250:         <PARAM NAME="Caption" VALUE="Pie Chart">

251:         <PARAM NAME="FontName" VALUE="Verdana">

252:         <PARAM NAME="FontHeight" VALUE="200">

253:         <PARAM NAME="FontCharSet" VALUE="0">

254:         <PARAM NAME="FontPitchAndFamily" VALUE="2">

255:         <PARAM NAME="FontWeight" VALUE="0">

256:     </OBJECT>

257:     <OBJECT ID="OptionButton2"

258:      CLASSID="CLSID:8BD21D50-EC42-11CE-9E0D-00AA006002f3"

                      STYLE="TOP:191pt;LEFT:396pt;WIDTH:108pt;HEIGHT:18pt;TABINDEX:5;

                      ZINDEX:7;">

259:         <PARAM NAME="BackColor" VALUE="2147483663">

260:         <PARAM NAME="ForeColor" VALUE="2147483666">

261:         <PARAM NAME="DisplayStyle" VALUE="5">

262:         <PARAM NAME="Size" VALUE="3810;635">

263:         <PARAM NAME="Caption" VALUE="Line Plot">

264:         <PARAM NAME="FontName" VALUE="Verdana">

265:         <PARAM NAME="FontHeight" VALUE="200">

266:         <PARAM NAME="FontCharSet" VALUE="0">

267:         <PARAM NAME="FontPitchAndFamily" VALUE="2">

268:         <PARAM NAME="FontWeight" VALUE="0">

269:     </OBJECT>

270:     <OBJECT ID="OptionButton3"

271:      CLASSID="CLSID:8BD21D50-EC42-11CE-9E0D-00AA006002f3"

                      STYLE="TOP:206pt;LEFT:396pt;WIDTH:108pt;HEIGHT:18pt;TABINDEX:6;

                      ZINDEX:8;">

272:         <PARAM NAME="BackColor" VALUE="2147483663">

273:         <PARAM NAME="ForeColor" VALUE="2147483666">

274:         <PARAM NAME="DisplayStyle" VALUE="5">

275:         <PARAM NAME="Size" VALUE="3810;635">

276:         <PARAM NAME="Caption" VALUE="Bar Graph">

277:         <PARAM NAME="FontName" VALUE="Verdana">

278:         <PARAM NAME="FontHeight" VALUE="200">

279:         <PARAM NAME="FontCharSet" VALUE="0">

280:         <PARAM NAME="FontPitchAndFamily" VALUE="2">

281:         <PARAM NAME="FontWeight" VALUE="0">

282:     </OBJECT>

283:     <OBJECT ID="OptionButton4"

284:      CLASSID="CLSID:8BD21D50-EC42-11CE-9E0D-00AA006002f3"

                      STYLE="TOP:224pt;LEFT:396pt;WIDTH:108pt;HEIGHT:18pt;TABINDEX:7;

                      ZINDEX:9;">

285:         <PARAM NAME="BackColor" VALUE="2147483663">

286:         <PARAM NAME="ForeColor" VALUE="2147483666">

287:         <PARAM NAME="DisplayStyle" VALUE="5">

288:         <PARAM NAME="Size" VALUE="3810;635">

289:         <PARAM NAME="Caption" VALUE="Area Graph">

290:         <PARAM NAME="FontName" VALUE="Verdana">

291:         <PARAM NAME="FontHeight" VALUE="200">

292:         <PARAM NAME="FontCharSet" VALUE="0">

293:         <PARAM NAME="FontPitchAndFamily" VALUE="2">

294:         <PARAM NAME="FontWeight" VALUE="0">

295:     </OBJECT>

296:     <OBJECT ID="CheckBox1"

297:      CLASSID="CLSID:8BD21D40-EC42-11CE-9E0D-00AA006002f3"

                      STYLE="TOP:264pt;LEFT:396pt;WIDTH:99pt;HEIGHT:17pt;TABINDEX:8;

                      ZINDEX:10;">

298:         <PARAM NAME="BackColor" VALUE="2147483663">

299:         <PARAM NAME="ForeColor" VALUE="2147483666">

300:         <PARAM NAME="DisplayStyle" VALUE="4">

301:         <PARAM NAME="Size" VALUE="3493;600">

302:         <PARAM NAME="Caption" VALUE="Horizontal Grid">

303:         <PARAM NAME="FontName" VALUE="Verdana">

304:         <PARAM NAME="FontHeight" VALUE="200">

305:         <PARAM NAME="FontCharSet" VALUE="0">

306:         <PARAM NAME="FontPitchAndFamily" VALUE="2">

307:         <PARAM NAME="FontWeight" VALUE="0">

308:     </OBJECT>

309:     <OBJECT ID="CheckBox2"

310:      CLASSID="CLSID:8BD21D40-EC42-11CE-9E0D-00AA006002f3"

                      STYLE="TOP:280pt;LEFT:396pt;WIDTH:99pt;HEIGHT:17pt;TABINDEX:9;

                      ZINDEX:11;">

311:         <PARAM NAME="BackColor" VALUE="2147483663">

312:         <PARAM NAME="ForeColor" VALUE="2147483666">

313:         <PARAM NAME="DisplayStyle" VALUE="4">

314:         <PARAM NAME="Size" VALUE="3493;600">

315:         <PARAM NAME="Caption" VALUE="Vertical Grid">

316:         <PARAM NAME="FontName" VALUE="Verdana">

317:         <PARAM NAME="FontHeight" VALUE="200">

318:         <PARAM NAME="FontCharSet" VALUE="0">

319:         <PARAM NAME="FontPitchAndFamily" VALUE="2">

320:         <PARAM NAME="FontWeight" VALUE="0">

321:     </OBJECT>

322: </DIV>


Notice that the definition of the Chart object contains random data. You can remove the PARAM tags that assign values to the Data array, or assign the same values to this array and the first few cells of the grid so that when the document is loaded, the graph will match the data on the grid.

Another item worth noticing is the assignment of titles to the grid's fixed cells. This action takes place when the layout is loaded. Because the cells of the first column and row are fixed, the user cannot edit them at runtime.

The GridChart application doesn't contain any error handlers. For example, it assumes that the user has already selected a range of cells before he or she attempts to plot them, and that they contain numeric data. If this isn't true, an error message will be displayed and the program will stop. There's a lot you can do to improve not only the application's interface and appearance, but its operation too. GridChart is a good starting point for a data-plotting applications, but there is quite a bit of error checking you can add to the program.

Review

The last example of this section demonstrates two very flexible controls that are commonly used together: the Grid control and the Chart control. Although the Grid control was designed to facilitate the display of data in a spreadsheet arrangement, with a few lines of code in its KeyDown and KeyPress events, you can turn it into a data-entry tool. The Chart control displays numeric data, like the ones stored on a Grid control, as graphs.

The two controls have more functional similarities, too. They both manipulate data stored in a two-dimensional array. The two-dimensional structure of the Grid's data is rather obvious. The Chart control uses a similar arrangement for storing multiple datasets, with as many data points per dataset. To access a cell in a grid, you must specify its address, which is the row and column number of the cell. To access a data point in a Chart control, you must specify the dataset it belongs to, and its order in the dataset. The address of a cell in a Grid control is specified with the help of the Row and Col properties, and a data point in a Chart control is specified with the RowIndex and ColIndex properties. Once the address of an element has been specified with the properties mentioned here, you can use the Text property of the Grid control or the DataItem property of the Chart control to read or set its value. The two controls provide a number of properties for specifying the appearance of the data or the chart, but you can easily figure out most of them, or experiment with the various settings to get what you want.