## Day 19 — Unit VI (Additional Topics)

• Roll

### Unit V CD Review

[ Present solution to CD V.1a ]  Respond to questions/issues.

### Project Proposals

Don't forget that you need to be preparing your project proposal and scheduling a meeting with me.

### Arrays

#### Introduction

This or similar information was presented last time.

Repetition is probably the one thing that makes computer programs as useful as they are. What is to be repeated? You can certainly repeat simple actions, but the real power comes from repeating the same action on similar kinds of data. That data can be an item in an array or a line from a file. We'll start with arrays.

An array is a collection of data items. The collection has a name (the declared variable) and items in the array are referred to by using an index. This is very similar to strings that have positions of each individual character. For example, we might have a set of scores. As with other data, we have to declare array variables and we do so in a manner similar to what we have done before, i.e.,

```    Dim scores(20) As Double
```

What this declaration does is to set aside space for a number of scores. How many scores? ... 21 In Visual Basic, when we declare and array we indicate the last/greatest valid index. Since, as with strings, the first element is at position 0 and the last valid position or index is 20, we have 21 items in the array.

As noted above, there is much power in arrays and repetition. For example if we want to assign each item in the array a random value between 0 and 100 we could use the following code.

```    Dim scores(20) As Double
Dim i As Integer

For i = 0 to 20
scores(i) = Fix(Rnd() * 101)
Next i
```

And if we wanted to get the average of the scores all that is necessary is:

```    Dim sum, average As Double
sum = 0

For i = 0 to 20
sum += scores(i)
Next i
average = sum / 21
```

The same code could be used to process 100 values or 1,000 or 1,000,000. No additional code would be necessary.   Questions? Comments? wonderings?

#### Shuffling cards example

If you were doing a card game program (e.g., poker) you would need to represent the deck of cards and have a means for shuffling the deck. A common approach to this task is to load an array with integers representing the cards. We need space for 52 cards (e.g., `Dim deck(51) as Integer`. To initialize the deck of cards we'd use a simple For loop.

```    For i As Integer = 0 to 51
deck(i) = i
Next i
```

To shuffle we will use a very clever and neat little trick. We'll just randomly swap cards but do so an organized way. We will swap a random card with the "last" card, then reduce last by 1 and do it again and then repeat that process. The code would look something like:

```    Dim temp, posit, last As Integer

For last = 51 to 1 Step -1
posit = Fix(Rnd()*last)
temp = deck(last)
deck(last) = deck(posit)
deck(posit) = temp
Next i
```

Questions? Comments? wonderings?   Note that swapping the values required the use of a temporary variable to store result. We cannot just assign one variable the value of the other and then assign the value of the second the value of the first. That would make them have the same value.

### Files

The task I am going to program is to calculate the standard deviation of a set of scores. The scores are in a file with one number on each line. The number on the first line indicates how many scores are to be processed. When I get done I will write the data and standard deviation out to a different, new file. Also, I use a menu item to allow the possibility of creating a file of values to work on.Any questions or wonderings?

#### The Code

The code for the program is given below. Most of the code will be for a button handler either directly or indirectly through subroutines. There are some class variables that allow for easy communication between the subroutines. There is also the code to have the program create the data file which calls for the use of the `Randomize` method.

```    '........... Class variables
Dim scores(100), sum, scoreCount As Integer
Dim mean, stdDev As Double
Dim reptSummary As String

Dim fileName As String
Dim i As Integer

OpenFileDialog1.Title = "File of numbers to open"
If OpenFileDialog1.ShowDialog = DialogResult.OK Then
fileName = OpenFileDialog1.FileName

If scoreCount > 100 Then     'increase array size if needed
ReDim scores(scoreCount)
End If

sum = 0
i = 1

Do Until i > scoreCount Or scoreReader.EndOfStream
sum += scores(i)
i += 1
Loop

mean = sum / scoreCount

End If
End Sub

Private Sub CalculateStandardDeviation()
Dim sum As Double

sum = 0
For i = 1 To scoreCount
sum += (scores(i) - mean) ^ 2
Next

stdDev = (sum / scoreCount) ^ 0.5
End Sub

Private Sub ReportResults()
Dim reptSummary As String
reptSummary = "count:" & vbTab & scoreCount.ToString & vbNewLine _
& "average:" & vbTab & mean & vbNewLine _
& "std.dev.:" & vbTab & stdDev.ToString
MessageBox.Show(reptSummary)

' ............... Record results on file
Dim resultWriter As IO.StreamWriter
resultWriter = IO.File.CreateText("results.txt")

resultWriter.WriteLine(reptSummary)

For i = 1 To scoreCount
resultWriter.WriteLine(scores(i).ToString)
Next
resultWriter.Close()
End Sub

Randomize()
Dim hi, lo, count, randomVal As Integer
count = InputBox("How many random values?")
lo = InputBox("Lowest possible random value?")
hi = InputBox("Highest possible random value?")

Dim fileName As String = InputBox("File name?")
Dim output As IO.StreamWriter
output = IO.File.CreateText(fileName)
output.WriteLine(count)

For i As Integer = 1 To count
randomVal = Fix(Rnd() * (hi - lo + 1)) + 1
output.WriteLine(randomVal)
Next i

output.Close()
End Sub

Private Sub btnCalculate_Click(sender As Object, e As EventArgs) Handles btnCalculate.Click

CalculateStandardDeviation()

ReportResults()
End Sub
```

Discussion about files, arrays, user-defined subroutines, file dialogs, & menustrip usage is provided below. The information refers to the code above. Ask questions about anything that is not clear.

#### Files

There are four steps in using a file—1) declare a variable for accessing the file; 2) open the file; 3) use the file (read from or write to it); 4) close the file. Those are discussed in more detail below.

1. declare a file

Files have internal and external names. External names are what we seen in our folders. They also contain the "path" information. In VB, there is a default and easy to use location for files — the `bin/Debug` folder. I suggest you always use that (in our class at least). Otherwise, your program may not work if it is run on someone else's computer.

Declaring a file typically includes preparing variables for the internal file name and the external file name. The internal name will be a `StreamReader` or a `StreamWriter` depending on whether you are reading from or writing to a file. We will be doing both. The external file name is a string that contains the name of the (it can be a variable or a literal, we'll use a variable). Often, the programmer will know in advance what the files are to be called and the following code will be applicable.

```    Dim scoreReader As IO.StreamReader
fileName = "scores.txt"
...
Dim resultWriter As IO.StreamWriter
```

Sometimes, though, you will want to allow the user to identify the filename. You could do so by asking for the name of the file and using a program statement like:

```    fileName = InputBox("File name?")
```

Or, alternatively, you can allow the user to browse for the file by using a file dialog. The following code provided that capability.

```    OpenFileDialog1.Title = "File of numbers to open"
If OpenFileDialog1.ShowDialog = DialogResult.OK Then
fileName = OpenFileDialog1.FileName
...     'whatever else is done if a file was selected by the user
End If
```

To use this you have to add an `OpenFileDialog` control to your form. (It doesn't show on the form but is included below it in the Visual Studio window. This allows the user to browse to find and select a file. The `If` statement is necessary to avoid doing something when the user does not select a file. Also note that the openfiledialog control has a property that contains the name of the file the user selected. Questions/Comments/Wonderings?

2. open the file

Opening a file for reading uses the `.OpenText()` method (as shown below). Opening a file for writing use the `.CreateText()` method (shown below) when you want a new file or to replace an existing file. If you want to add text to a file instead of creating a new file, use the `.AppendText()` method. All these methods require that you supply the external file name as a parameter to the method.

```    scoreReader = IO.File.OpenText(fileName)
...
resultWriter = IO.File.CreateText("results.txt")
```
3. get data from (or put data into) the file

To use the file requires reading data from it (into some variable) or writing data to it from a variable or by building the string you want to put in the file. Keep in mind that the file consists of text. On input, VB will convert the string values to numbers according to its rules. I assume numbers would also be converted to text on output (but recommend you use the `ToString` method. I use the `Val()` and `ToString` methods (because I have a touch of OCD).

```    scores(i) = Val(scoreReader.ReadLine())
...
resultWriter.WriteLine(scores(i).ToString)
```
4. close the file

When you are done reading or writing the file, you should always close it. The `.Close()` method works for files being read from and files being written to.

```    scoreReader.Close()
...
resultWriter.Close()
```

#### Arrays

An array is a collection of values. Each value must be of the same type, i.e., you can have an array of `Integer` values, an array of `String` values, an array of `Double` values, an array of `TextBox` values, an array of `RadioButton` values, etc. As with other variables you have to declare arrays and you do so with a `Dim` statement, e.g.,

```    Dim  scores(100) As Integer
```

The above code indicates we have a variable called scores and the last valid index is 100 — thus we have 101 values: `score(0)`, `score(1)`, `score(2)`, ..., `score(99)`, `score(100)`. In the declaration, the 100 is the last valid index or subscript. I typically ignore the 0th location. A subscript indicates which of the values you are using. Subscripts can be any expression that evaluates to an integer.

You use a subscripted variable just like any other variable—just be sure that you are using the particular value from the collection that you wish, i.e., that the subscript has the correct value. (You never, or almost never, use the collection variable without a subscript.) In our example (in the subroutine) we store a value in the array, then add that value to a sum, and we take care to increment the index/subscript so we don't put a new value in the same spot.

```    scores(i) = Val(scoreReader.ReadLine())
sum += scores(i)
i += 1
```

Once we have the values in the array, we can use them to do most anything we want. In our case we want to calculate the squares of the differences between each score and the mean and we later want to print the scores as part of our report.

```    For i = 1 To scoreCount
sum += (scores(i) - mean) ^ 2
Next
...
For i = 1 To scoreCount
resultWriter.WriteLine(scores(i).ToString)
Next
```

Remember that we used `Dim` to declare and indicate the size of the array. You can change that value while the program is running by using `Redim`. This allows us to make the array bigger if needed. If the array already have some values stored in it we would need to use `ReDim scores(scoreCount) Preserve`.

```    scoreCount = Val(scoreReader.ReadLine())
If scoreCount > 100 Then     'increase array size if needed
ReDim scores(scoreCount)
End If
```

When you are processing an array of values you need to be careful to not go try to access a position in the array that is not there. Thus, there are two conditions that could cause the end of the repetition for reading the values in the array. We might have read the number of lines indicated in the first line in the file or we might have come to the end of the file. The `.EndOfStream` property will have either a value of true or false depending on whether there is no more data.

#### Modularization via Subroutines (& Functions)

We have been using subroutines in all our code, but the VB system automatically generated them for us when we clicked on a button in the form or on the form itself. When you create your own subroutines it is like writing a new instruction for the computer. You name the new instruction and tell the computer how to do it. For example, when I thought of doing this program the main part of the code seemed to consist of three tasks:  1) read the scores;  find the standard deviation;  3) report. In thinking about those things I knew that I had to store all the values in the array and that I would need to add them all up (to find the mean). I decided to do those two things at the same time instead of having two loops to do them separately. So, at the more abstract or general level my task was to:

```    ReadScoresAndCalculateMean()

CalculateStandardDeviation()

ReportResults()
```

Since that was the way I thought about the problem, I just left the solution that way and planned to create a subroutine for each of those tasks. That way (six months from now) I can easily see how I went about the problem in general and can still look at the details in the subroutines if I want to see more specifically how the problem was solved.

A subroutine can access data in three ways:

• local variable declared inside the subroutine
• values passed in as parameters
• class variables

Be careful when naming variables. If two variables have the same name, only the most local one can be used. That is usually what is wanted but not always.

One way to get a file of values is to create it with a text editor, then place it in the `bin | debug` folder. You could also use a spreadsheet to automatically generate your random numbers. You would then save the file as a `.csv` (comma separated values) file. (And still place in the the `bin | debug` folder.) Another alternative is to have your program generate the file. I added that capability to this program using a menu.

To use a menu, you merely add the menustrip control to your form. When you do so, the menustrip control will appear at the bottom of the project window (like the openfiledialog did). But a menustrip also appears at the top of the form and you are allowed to enter names for menu items and sub-menu items. I chose to use File and Create as menu names. When I wanted to produce code that should get executed when I select the Create menu item, I just double-click it and the subroutine is automatically generated (as if I had done a button). Then, it is just a matter of developing the code to solve my problem. In this case:

```    Randomize()
Dim hi, lo, count, randomVal As Integer
count = InputBox("How many random values?")
lo = InputBox("Lowest possible random value?")
hi = InputBox("Highest possible random value?")

Dim fileName As String = InputBox("File name?")
Dim output As IO.StreamWriter
output = IO.File.CreateText(fileName)
output.WriteLine(count)

For i As Integer = 1 To count
randomVal = Fix(Rnd() * (hi - lo + 1)) + 1
output.WriteLine(randomVal)
Next i

output.Close()
```

### Next Time

• sharing data between forms

## Day 20 — Unit VI (Additional Topics)

• Roll

### Project Proposals

Don't forget that you need to be preparing your project proposal and scheduling a meeting with me.   Any comments, questions, wonderings?

### Sharing Data Between Forms

VB forms are able to share data but only in particular ways. Hopefully, the material below and the sample program in the notes directory (DataSharing.zip) will provide guidance as to how you can make your forms share data. I show several techniques, so be careful as you read about and try to use any of them.

#### Forms after the "start" form

Typically the start form is one of a kind and is accessed using its "name". Any form can access the start form's controls and public class variables. Our example is of a form that can add something to the start form's listbox and change values of its variables, e.g.,

```	Start.lstStartsList.Items.Add("value to be added")
Start.count += 1
Start.values(Start.count) = "whatever you want it to be"
```

Note that any form in the program should be able to do this.   Questions/Comments/Wonderings?

#### From a "calling/parent form" to its "child"

For other kinds of sharing the situation is a little different. Our programs will typically have the start form create or call other forms via `???.ShowDialog()` or `???.Show()`. The "calling" (or "creating" or "parent") form creates the form and can set values for its controls and public class variables. The direction of the sharing is forward rather than back as with the start form discussed above. Typically, the values will be set before the new or child form is "shown", i.e.,

```	Dim nextForm as formName
nextForm = New formName
nextForm.publicVariable = "data placed in the next form's public string variable"

nextForm.ShowDialog()
```

(The values in italics are made up names for variables and controls.) Again, a calling form can set or change the values of any public variables and control properties in the form about to be shown before it is shown.

One could use tis technique to pass data from one calling form to the next and the next calling form to the one after it and so on and so on and so on ...

#### From a "child" form to its "caller/parent"

Occasionally, a form will want to pass data to the form that called it. If the calling form was the start form there is no problem. In other cases, however, it is not so straightforward.

Object oriented languages have the notion of parent or caller, but Visual Basic seems not to implement it in a way that is directly available to child/called form. The solution is to have the caller/parent form tell the child/called form who its caller/parent is. The programmer must realize the need for this kind of communication and plan for it by creating a public variable in the child/called form that is the same type as the caller/parent form. Then, ...

• caller/parent sets the value of that variable (storing itself, `Me`, in it)
• called/child is shown
• called/child does whatever processing it needs before saving the value back in the caller/parent
• called/child uses the value in its public caller/parent variable to access the caller/parent's public variables or controls

Assuming we have forms start, first, and second and that first has a listbox called `lstOrder`, the following code could allow code in appear second to change the listbox in first.

• In second, declare the needed public class variable
```    Public caller As first
```
• In first, declare the variable for "second", instantiate it, set its `caller`, and show it
```    Dim nextForm as second
nextForm = New second
nextForm.caller = Me
nextForm.ShowDialog()
```
• In second, determine and add a value to "first's" list box
```    Dim valueToAdd As ...
' ... code to determine the value