Confused about Arrays in VB.net - arrays

I'm working on a project for college in which I have to create a program which stored twenty questions and answers entered on a teachers form which are then displayed one after the other (after clicking the next button) on a student form.
the issue I'm having is that I can enter the questions and answers ( array 0 to 19) however when the students are answering the questions only 19 are shown with the last question not appearing.
Let me know what I can show you to help solve my issue.
Module Module1
Public myQ(0 To 19) As String
Public myA(0 To 19) As String
End Module
Public Class frmTeacher
Public myCounter As Integer
Private Sub frmTeacher_Load(sender As Object, e As EventArgs) Handles MyBase.Load
myCounter = (0)
End Sub
Private Sub btnTeacherNext_Click(sender As Object, e As EventArgs) Handles btnTeacherNext.Click
If myCounter < 19 Then
myQ(myCounter) = txtTeacherQ.Text
myA(myCounter) = txtTeacherA.Text
myCounter = myCounter + 1
txtTeacherQ.Text = ""
txtTeacherA.Text = ""
Else
MsgBox("20 Questions Created, Moving on To Student Screen")
Me.Hide()
frmStudent1.Show()
End If
End Sub
Public Class frmStudent1
Dim myScore As Integer
Dim MyCounter2 As Integer
Public myNames As String
Private Sub btnStudentHelp_Click(sender As Object, e As EventArgs) Handles btnStudentHelp.Click
MsgBox("Questions will be shown to the left, Place your answer into the box on the right and click next")
End Sub
Private Sub frmStudent1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
lblStudentQ.Text = myQ(0)
HideItAll()
txtStudentName.Visible = True
btnStart.Visible = True
End Sub
Private Sub HideItAll()
lblStudentQ.Visible = False
txtStudentA.Visible = False
txtStudentName.Visible = False
btnStudentHelp.Visible = False
btnNextStudent.Visible = False
btnStart.Visible = False
btnStudentNext.Visible = False
End Sub
Private Sub btnStudentNext_Click(sender As Object, e As EventArgs) Handles btnStudentNext.Click
If MyCounter2 < 19 Then
If txtStudentA.Text = myA(MyCounter2) Then
myScore = myScore + 1
End If
MyCounter2 = MyCounter2 + 1
lblStudentQ.Text = myQ(MyCounter2)
Else
MsgBox("Your score is " + Str(myScore))
myNames = myNames + txtStudentName.Text + ": " + Str(myScore) + vbNewLine
HideItAll()
btnNextStudent.Visible = True
End If
End Sub
Private Sub btnNextStudent_Click(sender As Object, e As EventArgs) Handles btnNextStudent.Click
Me.Refresh()
HideItAll()
txtStudentName.Visible = True
btnStart.Visible = True
End Sub
Private Sub btnStart_Click(sender As Object, e As EventArgs) Handles btnStart.Click
myScore = 0
MyCounter2 = 0
If txtStudentName.Text = "teacher" Then
MsgBox("The scores are as follows: " + vbNewLine + myNames)
End If
HideItAll()
lblStudentQ.Visible = True
txtStudentA.Visible = True
btnStudentHelp.Visible = True
btnStudentNext.Visible = True
End Sub
End Class

change this:
If MyCounter2 < 19 Then
to:
If MyCounter2 < 20 Then
or:
If MyCounter2 <= 19 Then

When you declare your arrays as
Public myQ(0 To 19) As String
you have effectively created an array that could hosts 20 strings and their indexes are from 0 to 19 max. This means that your myCounter2 variable could have as maximum value 19 otherwise you go out of bound of the array. At the same time if you show only the questions and answers that have an index less that 19 you loose the last couple of question/answer
You should fix your code using this kind of conditional
If MyCounter2 < myQ.Length Then
.....
Array.Length returns the number of elements that could be stored in all the dimensions of the array (20).
Using this property is better because, if you change the array size (say you want to ask 40 questions getting 40 answers) then you don't need to check every line of your code to adjust magic numbers appearing everywhere.
But, after the change, this line of the btnStudentNext_Clicks event fails when MyCounter2 value is 19
' MyCounter2 = 19 + 1
MyCounter2 = MyCounter2 + 1
' this fails because at this point MyCounter2 is 20
lblStudentQ.Text = myQ(MyCounter2)
A possible refactoring of your code could be
Private Sub btnStudentNext_Click(sender As Object, e As EventArgs) Handles btnStudentNext.Click
If MyCounter2 < myQ.Length Then
If txtStudentA.Text = myA(MyCounter2) Then
myScore = myScore + 1
End If
MyCounter2 = MyCounter2 + 1
End if
if MyCounter2 >= myQ.Length Then
ShowResults();
else
lblStudentQ.Text = myQ(MyCounter2)
txtStudentA.Text = ""
Endif
End Sub
Private Sub ShowResults()
MsgBox("Your score is " + Str(myScore))
myNames = myNames + txtStudentName.Text + ": " + Str(myScore) + vbNewLine
HideItAll()
btnNextStudent.Visible = True
End Sub

Related

VB.NET | Array of pictureboxes in panel: Object reference not set to an instance of an object

In the code below I am attempting to change the tag of an existing control that was created in the array 'pictureboxes(9, 9)'. When I try to do this, I get the error 'Object reference not set to an instance of an object.'. This is done in the checkdata sub, near the bottom of the code with the comment 'Object reference not set to an instance of an object.'.
The string that is passed through to the sub is a long string of numbers, and the pictureboxes are placed into a layoutpanel if that is helpful.
I understand what this error means, I am aware that pictureboxes(i, j) is = nothing when breakpointed; I just don't know how to fix it :s
Any help is greatly appreciated and hopefully I will be quick to answer any comments/answers.
Thank you
Imports System.Net.Sockets
Imports System.Threading
Imports System.Text
Imports System.Net
Public Class Form1
'0 as default tile, 1 as clicked, 3 as set mine (host perspective)
Dim tiles() As Integer = {0}
Public pictureboxes(9, 9) As PictureBox
Dim flagged() As Integer
Dim clicked As Integer()
Dim columns As Integer = 10
Dim rows As Integer = 10
Dim placedMinesCount As Integer = 0
Dim formattedTag As String()
Public turn As Boolean = False
Dim stringToSend As String
Public Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
For i As Byte = 0 To 9
For j As Byte = 0 To 9
pictureboxes(i, j) = New PictureBox
pictureboxes(i, j).Height = 60
pictureboxes(i, j).Width = 60
pictureboxes(i, j).ImageLocation = "0.png"
pictureboxes(i, j).Tag = "0|" & i & ", " & j
AddHandler pictureboxes(i, j).Click, AddressOf Tile_Click
Dim column As Integer = j
Dim row As Integer = i
Panel.Controls.Add(pictureboxes(i, j), column, row)
Next
Next
If Login.isHost = True Then
Me.Text = "Set your mines (10)"
turn = True
ElseIf Login.isHost = False Then
Me.Text = "Await your turn"
btnEndTurn.Visible = False
btnEndTurn.Enabled = False
End If
End Sub
Protected Sub Tile_Click(ByVal sender As Object, ByVal e As EventArgs)
formatSenderTag(sender.tag)
If Login.isHost = True Then
Dim clickAction As String = formattedTag(0)
Select Case clickAction
Case "0"
If placedMinesCount < 10 Then
placedMinesCount = placedMinesCount + 1
sender.imagelocation = "3.png"
sender.tag = "3"
Me.Text = "Set your mines (" & 10 - placedMinesCount & ")"
ElseIf placedMinesCount >= 10 Then
MsgBox("You have placed all of your 10 Mines")
End If
Case "2"
MsgBox("You cannot set a mine here")
Case "3"
placedMinesCount = placedMinesCount - 1
Me.Text = "Set your mines (" & 10 - placedMinesCount & ")"
sender.imagelocation = "0.png"
sender.tag = "0"
End Select
ElseIf Login.isHost = False Then
Dim clickAction As String = formattedTag(0)
Select Case clickAction
Case "0"
sender.tag = "1"
sender.imagelocation = "1.png"
Case "3"
MsgBox("Game Over")
Case "2"
MsgBox("Already Clicked")
End Select
End If
End Sub
Private Sub formatSenderTag(ByVal sender As String)
'split into array
'element 0 as TILE TYPE
'element 1 as TILE LOCATION
formattedTag = sender.Split(New String() {"|"}, StringSplitOptions.None)
End Sub
Private Sub Form_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
End
End Sub
Private Sub btnEndTurn_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnEndTurn.Click
turn = False
gridtostring()
senddata()
End Sub
Private Sub gridtostring()
For i As Byte = 0 To 9
For j As Byte = 0 To 9
formatSenderTag(pictureboxes(i, j).Tag & "|")
stringToSend = stringToSend & formattedTag(0)
Next
Next
End Sub
Private Sub senddata()
'***SEND STUFF
'Assuming you have a textbox with the data you want to send
If (Not String.IsNullOrEmpty(stringToSend)) Then
Dim data() As Byte = Encoding.ASCII.GetBytes(stringToSend)
Login.sendingClient.Send(data, data.Length)
End If
End Sub
Public Sub checkdata(ByVal data As String)
If Not data = stringToSend Then
'Dim loopcount As Integer = 0
For i As Byte = 0 To 9
For j As Byte = 0 To 9
Dim loopcount As Integer = (i.ToString & j.ToString) + 1
'Dim pineapple As String = pictureboxes(i, j).Tag
'pictureboxes(i, j).Tag = GetChar(data, 3)
pictureboxes(i, j).Tag = GetChar(data, loopcount) & "|" & i & ", " & j '***Object reference not set to an instance of an object.***
formatSenderTag(pictureboxes(i, j).Tag)
pictureboxes(i, j).ImageLocation = formattedTag(0)
pictureboxes(i, j).ImageLocation = "0.png"
'Panel.Controls(pictureboxes(i, j).Tag) = GetChar(data, 3) '.Tag = GetChar(data, 3)
Next
Next
End If
End Sub
End Class
***AND BELOW IS THE OTHER FORM WHICH CALLS CHECKDATA()
Imports System.Net.Sockets
Imports System.Threading
Imports System.Text
Imports System.Net
Public Class Login
Dim Port As Integer = 8123
Private Const broadcastAddress As String = "255.255.255.255"
Public receivingClient As UdpClient
Public sendingClient As UdpClient
Dim sendAddress As String
Dim ServerMode As Boolean = False
Public isHost As Boolean = true
Dim returndata As String
Private Sub Login_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
End Sub
Private Sub ComboWANLAN_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles ComboWANLAN.SelectedIndexChanged
If ComboWANLAN.Text = "Online (WAN)" Then
txtSendAddress.Enabled = True
ElseIf ComboWANLAN.Text = "Offline (LAN)" Then
txtSendAddress.Enabled = False
End If
End Sub
Private Sub btnConnect_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnConnect.Click
'***START PORT LISTENING/SENDING AND NETWORKING STUFFS
Port = txtPort.Text
InitializeSender()
InitializeReceiver()
End Sub
Private Sub btnHost_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnHost.Click
'***START PORT LISTENING/SENDING AND NETWORKING STUFFS
Port = txtPort.Text
InitializeSender()
InitializeReceiver()
isHost = True
Me.Hide()
Form1.Show()
End Sub
Private Sub InitializeSender()
If ComboWANLAN.Text = "Offline (LAN)" Then
sendingClient = New UdpClient(broadcastAddress, Port)
'Use broadcastAddress for sending data locally (on LAN), otherwise you'll need the public (or global) IP address of the machine that you want to send your data to
ElseIf ComboWANLAN.Text = "Online (WAN)" Then
sendAddress = txtSendAddress.Text
sendingClient = New UdpClient(sendAddress, Port)
'Use broadcastAddress for sending data locally (on LAN), otherwise you'll need the public (or global) IP address of the machine that you want to send your data to
End If
sendingClient.EnableBroadcast = True
End Sub
Private Sub InitializeReceiver()
receivingClient = New UdpClient(Port)
ThreadPool.QueueUserWorkItem(AddressOf Receiver) 'Start listener on another thread
End Sub
Private Sub Receiver()
Dim endPoint As IPEndPoint = New IPEndPoint(IPAddress.Any, port) 'Listen for incoming data from any IP on the specified port
Do While True 'Notice that i've setup an infinite loop to continually listen for incoming data
Dim data() As Byte
data = receivingClient.Receive(endPoint)
If Form1.turn = False Then
returndata = Encoding.ASCII.GetString(data) 'Recived data as string
Form1.checkdata(returndata)
End If
Loop
End Sub
Private Sub Form_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
End
End Sub
End Class
***STACK TRACE
at Minesweeper.Form1.checkdata(String data) in c:\users\harry\documents\visual studio 2010\Projects\Minesweeper\Minesweeper\Form1.vb:line 139
at Minesweeper.Login.Receiver() in C:\Users\Harry\Documents\Visual Studio 2010\Projects\Minesweeper\Minesweeper\Login.vb:line 71
at Minesweeper.Login._Lambda$__1(Object a0) in C:\Users\Harry\Documents\Visual Studio 2010\Projects\Minesweeper\Minesweeper\Login.vb:line 61
at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
at System.Threading.ThreadPoolWorkQueue.Dispatch()
at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
Note: Screwed up with the spacings in some places
This code does not give an error with the data you gave:
checkdata("00000000000000000000000000000000000000000000000000000000000000000000000000000000‌​00000000000000000000")
Public Sub checkdata(ByVal data As String)
If Not data = stringToSend Then
'Dim loopcount As Integer = 0
For i As Byte = 0 To 9
For j As Byte = 0 To 9
Dim loopcount As Integer = (i.ToString & j.ToString) + 1
'Dim pineapple As String = pictureboxes(i, j).Tag
'pictureboxes(i, j).Tag = GetChar(data, 3)
pictureboxes(i, j).Tag = GetChar(data, loopcount) & "|" & i & ", " & j '***Object reference not set to an instance of an object.***
formatSenderTag(pictureboxes(i, j).Tag)
pictureboxes(i, j).ImageLocation = formattedTag(0)
pictureboxes(i, j).ImageLocation = "0.png"
'Panel.Controls(pictureboxes(i, j).Tag) = GetChar(data, 3) '.Tag = GetChar(data, 3)
Next
Next
End If
End Sub
Looking at your stack trace and code, you are missing the instantiation of Form1 in your login class. I think this can be the problem.
Try adding this to the beginning of your Login class:
Dim Form1 as New Form1

When adding data to the array it says System.IndexOutOfRangeException?

When adding a data to an array I keep getting the error 'System.IndexOutOfRangeException' the Array is declared to bound of 200 and at the data I'm trying to add is at 6 + 1, 6 is the variable count, in the code.
Public Class FormEvents
Dim ArrayEvents(200) As String
Dim Count As Integer
Private Sub FormEvents_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim Events As String = "C:\Users\Andrew prince\Desktop\Education\College\Computing\Controlled assesment\Program\Program files\Events.txt"
Dim ObjReader As New StreamReader(Events)
ArrayEvents = ObjReader.ReadLine().Split(",")
UpdateInfo()
ObjReader.Close()
TxtEventNo.Enabled = False
BtnAdd.Enabled = False
End Sub
Sub UpdateInfo()
TxtEventNo.Text = ArrayEvents(Count)
TxtEventType.Text = ArrayEvents(Count + 1)
TxtEventDistance.Text = ArrayEvents(Count + 2)
End Sub
Private Sub BtnNext_Click(sender As Object, e As EventArgs) Handles BtnNext.Click
Count = Count + 3
checkInfo()
End Sub
Private Sub BtnPrev_Click(sender As Object, e As EventArgs) Handles BtnPrev.Click
Count = Count - 3
checkInfo()
End Sub
Sub Createvent()
Dim eventNo As String
eventNo = Count / 3
TxtEventNo.Text = eventNo
TxtEventDistance.Text = ""
TxtEventType.Text = ""
BtnNext.Enabled = False
BtnPrev.Enabled = False
BtnAdd.Enabled = True
End Sub
Sub checkInfo()
If Count <= 0 Then Count = 0
If ArrayEvents(Count) = "" Then Createvent() Else UpdateInfo()
End Sub
Private Sub BtnAdd_Click(sender As Object, e As EventArgs) Handles BtnAdd.Click
If TxtEventDistance.Text.Length > 0 And TxtEventType.Text.Length > 0 Then AddToArray()
End Sub
Sub AddToArray()
ArrayEvents(Count) = TxtEventNo.Text
ArrayEvents(Count + 1) = TxtEventType.Text 'error occurs here in the code
ArrayEvents(Count + 2) = TxtEventDistance.Text
Enable()
End Sub
Sub Enable()
BtnAdd.Enabled = False
BtnNext.Enabled = True
BtnPrev.Enabled = True
End Sub
End Class
ArrayEvents is probably no longer 200 in length after you set it in the load method to:
ArrayEvents = ObjReader.ReadLine().Split(",")

VB displaying elements from multidimensional array in listbox

For some odd reason I am getting an error when I am using my loop to display the elements of my array. I can't seem to understand what it is I am doing or not doing right. This is the code so far. This is not for a class, I am learning myself.
Option Strict On
Option Explicit On
Option Infer Off
Public Class Form1
Private strExams(49, 2) As String
Dim count As Integer = 0
Private Sub btnAdd_Click(sender As Object, e As EventArgs) Handles btnAdd.Click
Dim strStudent As String = txtStudent.Text
Dim strTest As String = txtTest.Text
Dim strScore As String = txtScore.Text
If count <= 49 Then
strExams(count, 0) = strStudent
strExams(count, 1) = strTest
strExams(count, 2) = strScore
count += 1
End If
txtStudent.Text = String.Empty
txtTest.Text = String.Empty
txtScore.Text = String.Empty
txtStudent.Focus()
End Sub
Private Sub btnDisplay_Click(sender As Object, e As EventArgs) Handles btnDisplay.Click
Dim intHighRow As Integer = strExams.GetUpperBound(0)
Dim intHighCol As Integer = strExams.GetUpperBound(1)
Dim intR As Integer
Dim intC As Integer
Do While intC <= intHighCol
intR = 0
Do While intR <= intHighRow
lstMessage.Items.Add(strExams(intR, intC))
intR += 1
Loop
intC += 1
Loop
End Sub
This is the error I am getting when I click my display button.
An unhandled exception of type 'System.ArgumentNullException' occurred in System.Windows.Forms.dll
Additional information: Value cannot be null.
Try this. This makes much more sense to me. The reason you're getting a null error is that you haven't filled everything up in your array and your listbox can't list null items. So a workaround would be to enumerate only items that already have values, thus, just loop until the last value of count.
Private Sub btnDisplay_Click(sender As Object, e As EventArgs) Handles btnDisplay.Click
Dim intR As Integer
lstMessage.Items.Clear()
Do While intR < count
lstMessage.Items.Add(strExams(intR, 0) & " - " & strExams(intR, 1) & " - " & strExams(intR, 2))
intR += 1
Loop
End Sub

Two Dimensional Array VB

Ok so I am having problems adding elements into my 2d array. I am using 3 textboxes to allow a user to input items into my array. My problem is I cant seem to get the array to go past (0,2). I want the user to be able to add a row of inputs with each click of the add button. This is so far what I have in my code. Can anyone help? This is not for a class I am learning on my own.
Option Strict On
Option Explicit On
Option Infer Off
Public Class Form1
Private strExams(49, 2) As String
Private Sub btnAdd_Click(sender As Object, e As EventArgs) Handles btnAdd.Click
Dim strStudent As String = txtStudent.Text
Dim strTest As String = txtTest.Text
Dim strScore As String = txtScore.Text
Dim count As Integer = 0
If count <= 49 Then
strExams(count, 0) = strStudent
strExams(count, 1) = strTest
strExams(count, 2) = strScore
count += 1
End If
txtStudent.Text = String.Empty
txtTest.Text = String.Empty
txtScore.Text = String.Empty
txtStudent.Focus()
End Sub
Try this... Your count variable must be placed outside the btnAdd_Click sub or it will always reset back to 0, thus, you won't get past (0,2).
Option Strict On
Option Explicit On
Option Infer Off
Public Class Form1
Private strExams(49, 2) As String
Dim count As Integer = 0
Private Sub btnAdd_Click(sender As Object, e As EventArgs) Handles btnAdd.Click
Dim strStudent As String = txtStudent.Text
Dim strTest As String = txtTest.Text
Dim strScore As String = txtScore.Text
If count <= 49 Then
strExams(count, 0) = strStudent
strExams(count, 1) = strTest
strExams(count, 2) = strScore
count += 1
End If
txtStudent.Text = String.Empty
txtTest.Text = String.Empty
txtScore.Text = String.Empty
txtStudent.Focus()
End Sub

Why do I get an error when I am declaring a Matrix/Array as a global variable?

When I press Start in "Visual Studio 2011 Ultimate 12", where I am working, it says:
"InvalidOperationException was unhandled, an exception was caught by the debugger, and user settings indicate that a break should occur. This thread is stopped with only external code frames on the call stack. External code frames are typically from framework code but can also include other optimized modules which are loaded in a target process."`
My code:
Public Class Form1
Private matrix As Integer(,) = PopulateMatrix()
Private Sub ClickMouse(sender As Object, e As DataGridViewCellMouseEventArgs) Handles DataGridView.CellMouseClick
MsgBox(e.Clicks & e.ColumnIndex & e.RowIndex)
matrix(e.ColumnIndex, e.RowIndex) = 0
Matrixtomatrixdef(matrix)
End Sub
Private Function PopulateMatrix() As Integer(,)
Dim matrix(10, 10) As Integer
For rown = 0 To 9
For columnn = 0 To 9
matrix(columnn, rown) = 1
Next
Next
Return matrix
End Function
Private Sub Matrixtomatrixdef(matrix As Integer(,))
Dim Matrixdef(10, 10) As Integer
For rown = 0 To 9
For columnn = 0 To 9
Matrixdef(columnn, rown) = matrix(columnn, rown)
Debug.Write(Matrixdef(columnn, rown).ToString & " ")
Next
Debug.WriteLine("")
Next
End Sub
End Class
Because your trying to call the function as the class is being initialized, and you cannot do that. Declare the variable, but set it later like in the constructor or at another appropriate point.
Private matrix As Integer(,)
Public Sub New() 'constructor
matrix = PopulateMatrix
End Sub
You can't call a method on the same object as part of the field definition. Instance methods are only available after all fields have been initialized.
The correct code:
Private matrix As Integer(,)
Private Sub populate1s(sender As Object, e As EventArgs) Handles Button3.Click
matrix = PopulateMatrix()
End Sub
Private Function PopulateMatrix() As Integer(,)
Dim matrix(10, 10) As Integer
For rown = 0 To 9
For columnn = 0 To 9
matrix(columnn, rown) = 1
Next
Next
Return matrix
End Function
Public Sub ClickMouse(sender As Object, e As DataGridViewCellMouseEventArgs) Handles LRInc.CellMouseClick
matrix(e.ColumnIndex, e.RowIndex) = 0
For rown = 0 To 9
For columnn = 0 To 9
Debug.Write(matrix(columnn, rown).ToString & " ")
Next
Debug.WriteLine("")
Next
End Sub

Resources