vb2010 Express - Operator '=' is not defined - vb.net

I'm building the retro arcade game 'Asteroids' and have been having some trouble with the collision detection of a 'shot' hitting an asteroid and splitting it into pieces.
Using the following code, I get an error in the If statement at the start of the second subroutine:
Operator '=' is not defined for types 'System.Windows.Forms.PictureBox' and 'System.Windows.Forms.PictureBox'.
Private Sub CollisionDetection_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CollisionDetection.Tick
Dim Asteroids() = {picLrgAsteroid100, picLrgAsteroid200, picLrgAsteroid300, picLrgAsteroid400, picLrgAsteroid500}
'Stores all asteroids, used for testing collision for all asteroids
For Each PictureBox In Asteroids
'For all asteroids
If PictureBox.Bounds.IntersectsWith(picBullet1.Bounds) Then
Me.Controls.Remove(picBullet1)
AsteroidDestroyer(PictureBox)
ElseIf PictureBox.Bounds.IntersectsWith(picBullet2.Bounds) Then
Me.Controls.Remove(picBullet2)
ElseIf PictureBox.Bounds.IntersectsWith(picBullet3.Bounds) Then
Me.Controls.Remove(picBullet3)
End If
'If it intersects with a bullet
'Remove the bullet, and transmit to break apart the asteroid
Next
End Sub
Public Sub AsteroidDestroyer(ByVal Asteroid As System.Windows.Forms.PictureBox)
If Asteroid = picLrgAsteroid100 Then
*
*
*
End if
As I'm using a for...each statement, how can I transmit which PictureBox is currently being run through "For each PictureBox in Asteroids", to the subroutine 'AsteroidDestroyer' and have it receive, then use it in the if statement?
Example (Pseudo-code):
sub CollisionDetection
If PictureBox (picLrgAsteroid100) intersects with picBullet1 then
Remove picBullet1
Transmit to AsteroidDestroyer(picLrgAsteroid100)
End if
End Sub
Sub AsteroidDestroyer(ByVal Asteroid as PictureBox)
If Asteroid = picLrgAsteroid100 then
End If
End Sub
And if you can see any way to improve, to avoid this problem, there's no reason I have it as I currently do, so feel free to suggest!

In lay terms, you are trying to compare two variables which contain references, and in this case, to the same object (or potentially the same object). Whereas the number one can "equal" the number one, or a variable containing the number one can "be equal to" another variable containing the number one, in contrast an object can not equal itself. Equality is a characteristic of the properties, or values of an object.
In the case of comparing references to an object vb.net provides the Is Operator. Where you might be accustomed to comparing values or properties with the equal sign,
If var1 = var2 Then
to perform a comparison of object references you would instead use ‘Is‘.
If objRef1 Is objRef2 Then
Both = and Is return a Boolean indicating a success or failure (equality/true, or inequality/false), but where the equal sign compares a value, Is compares a reference without regard to the reference's properties.
In your specific case, this translates to,
If Asteroid Is picLrgasteroid100 Then

Related

How to update a group of combo boxes using Loops

I have a form with combo boxes (cmbPort#) to select up to 8 serial ports. I want to first clear the item list for each, populate them with currently available system ports, and then add the option "Off" to each list. Finally, to set each combo box according to defaults saved in string spName(). I created a GroupBox (gBox1) and dragged each cmbPort onto it but I'm not sure how to reference the controls on it. I'm using VB 2015.
Can you help with VB.NET code to use loops ("For Each" or similar) to do this more efficiently?
Private Sub frmProp_Load(sender As Object, e As EventArgs) Handles MyBase.Load
cmbPort1.Items.Clear()
...
cmbPort8.Items.Clear()
For Each sp As String In My.Computer.Ports.SerialPortNames
cmbPort1.Items.Add(sp)
...
cmbPort8.Items.Add(sp)
Next
cmbPort1.Items.Add("Off")
...
cmbPort8.Items.Add("Off")
cmbPort1.Text = spName(1)
...
cmbPort8.Text = spName(8)
End Sub
Loops are an incredibly useful tool to master. I pitched here some code so you can get the idea, but I was working out of IDE so you might have to apply some fixes to this code to make it work as you want it to.
The main idea is that you shouldn't have to write a line more than once. If you multiply the same operation on several lines of code, you create potential problems for the future. Loops and subs are really helpful to prevent this kind of issues.
Private Sub frmProp_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'This is for later
Dim cmbIndex As Integer = 1
'You basically do the same operations for every Combobox in your list, son only one loop needed
For Each cmbPort As ComboBox In {cmbPort1, cmbPort2, cmbPort3 [...] cmbPort8} 'this is a way to declare an array
'Clear
cmbPort.Items.Clear()
'Add SerialPortNames
For Each sp As String In My.Computer.Ports.SerialPortNames
cmbPort.Items.Add(sp)
Next
'Add "Off"
cmbPort.Items.Add("Off")
'This last one is a little bit trickier because you want to match numbers
'This is the place where you get errors when something doesn't go as planned
'If you need to keep it inside the loop here's a way to achieve that, but honestly I would't do that
'Instead I would suggest that you take this part out of the loop and do it manually
If spName(cmbIndex) IsNot Nothing Then cmbPort.Text = spName(cmbIndex)
cmbIndex += 1
Next
End Sub
You shouldn't consider efficiency into this equation, as this operation will not be called all the time, only on load. I mean: you should always do things in the best way you can, but optimization is sometimes the enemy of good, readable code.

DataGridView with thread vb.net?

**I hav problem when i use DataGridView1 with thread
i get empty rows like image **
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim thread As New Thread(AddressOf grid)
thread.Start()
End Sub
Public Function grid()
For i As Int16 = 1 To 50
Invoke(Sub()
DataGridView1.Rows.Add(i)
DataGridView1.Refresh()
End Sub)
Next
End Function
https://i.stack.imgur.com/KOXRR.jpg
This is a perfect example of why you MUST read the relevant documentation, especially if something doesn't work the way you expect. If you had bothered to read the documentation for the Add method you're calling here then you'd have seen that that particular overload adds the specific number of rows to the grid and that's all. At no point does it populate those rows with any data. The code you have is going to add 1+2+3+4+...+48+49+50 empty rows to your grid. If what you actually want is to add a single row each time where i is the data displayed in that row then you need to call one of the overloads of Add that does that, or else call the overload with no arguments to add a single row, then get that row and set the Value of a cell explicitly.
EDIT: The simplest way to add a row with i as data is to call the overload of Add that takes an array of cell values. If you only have one cell, you use an array with one element:
DataGridView1.Rows.Add({i})
The braces indicate that the contents is an array. It's shorthand for this:
DataGridView1.Rows.Add(New Integer() {i})
Note that, if you pass a single Integer, the overload with a single Integer parameter will be called as it's the closest match. If you were to pass multiple discrete Integers, e.g.
DataGridView1.Rows.Add(i, i)
then you would not have the same problem because there is no overload with multiple Integer parameters. In that case, the overload that takes an array of Objects would be called. That overload's parameter is declared ParamArray, which means that you can pass either multiple individual objects or a single array. Another option would be to cast your Integer as type Object, which would also cause the overload that takes an array of Objects to be called:
DataGridView1.Rows.Add(CObj(i))
When you call an overloaded method, the closest valid match will be called, so be sure that your arguments match the parameters of the overload you want to call and make sure you understand what each overload does. ALWAYS read the documentation if you aren't 100% sure. The F1 key and the Help menu are there for a reason.

Need help can figure out this project in VB

This is what i have so far. cant seem to get it to work these are the guidelines
***Specifics
You will use 1 file to enter all the scores. The file is named Data.txt and should be stored in the projects Debug folder. The scores are floating point numbers.
One button should calculate the mean, range, and standard deviation and display them.
You must use separate functions to calculate the 3 statistics.
One button should display the frequencies in tabular form. For this exercise, the frequencies we are interested in are as follows:
# scores < 60
60 <= # scores < 70
70 <= # scores < 80
80 <= # scores < 90
90 <= # scores
You must use a separate array to hold the totals for the individual ranges.
All scores should be displayed in a listbox.*
Option Strict On
Public Class Form1
Private names() As String = IO.File.ReadAllLines("data.txt")
Private scores(names.Count - 1) As double
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
For i As Integer = 0 To names.Count - 1
scores(i) = CInt(names(i))
Next
End Sub
Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
Me.Close()
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim sum As Double = 0
mean(sum)
OutputListBox.Items.Add(sum)
End Sub
Function mean(ByRef sum As Double) As Double
Dim total As Double = scores(0)
For i As Double = 0 To scores.Count - 1
sum =
Next
Return sum
End Function
End Class
I won't do all of the work for you, but here is a restructuring of your form with the mean implemented and some comments so you can figure out what is happening:
Option Strict On
Option Explicit On
Partial Public Class Form1
Private scores() As Double
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Try
' Clear the list view
ListView1.Clear()
' First, load the scores from the file into memory
Call LoadScores()
Dim value As Double
' Next, calculate the mean
value = CalculateMean()
' And add it to the list view
ListView1.Items.Add("Mean = " & value.ToString)
' Now calculate the other items and display them
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
''' <summary>
''' This method loads the scores from the file into the scores array
''' </summary>
''' <remarks></remarks>
Private Sub LoadScores()
Dim stringScores() As String
' Read all of the scores in the file into an array of strings
stringScores = IO.File.ReadAllLines("data.txt")
' Resize the scores array to hold all of the values in the file
ReDim scores(stringScores.Length)
Dim counter As Integer
' Now convert those strings to numbers, and store them in scores
For Each sValue As String In stringScores
' Convert the string value from the file into a double and store it in the current location in the scores array
scores(counter) = CDbl(sValue)
' Keep track of our position in the scores array
counter += 1
Next
End Sub
''' <summary>
''' The mean is the sum of the scores divided by the total number of scores
''' </summary>
''' <returns></returns>
''' <remarks></remarks>
Function CalculateMean() As Double
If scores.Length <> 0 Then
Dim total As Double
For Each value As Double In scores
total += value
Next
Return total / scores.Length
Else
' Avoid a divide by zero error
Return 0
End If
End Function
Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
Me.Close()
End Sub
End Class
As with any problem, start by breaking it down and do one piece at a time. A common approach is to make one function implement one (or one part of a) requirement, so start there.
Read the file to get the scores. For this exercise, you have a hard-coded name, but it is just as easy to make the file reading function take the name as a parameter. You know the scores are listed as floating-point numbers, so you will return them as Double or Single. I see that you used an array in the code you have so far, so we'll stick with that. With that information, we can make the signature of the function
Public Function ReadScoresFromFile(fileName As String) As Double()
Calculate the mean, range, and standard deviation; three things, three functions. Based on the mathematical definitions of these three things, you will need functions that take in a sequence of numbers and will return one number. This should lead you to the function definitions:
Public Function Mean(values As Double()) As Double
Public Function Range(values As Double()) As Double
Public Function StandardDeviation(values As Double()) As Double
A quick search online or through your math/statistics book should give you definitions and formulas that you can turn into code. Hint: You may be able to call one function from one of the others to simplify the work.
Group scores into ranges. As with the file name, you have a specified list of ranges. You could try to parametrize the function to take the ranges as an argument, but its probably not worth the effort for this exercise. So, we know have a sequence of scores and need a list of total of number of scores in each range. Since totals will be integral numbers and not floating-point, we'll pick the type accordingly.
Public Function CountInRanges(scores as Double()) As Integer()
At this point, you have all the functions you need to get the data you need. Now you just have to make the various button click handlers call the appropriate functions and put the results in the appropriate labels, list boxes, etc. Use the arguments and return types to help you figure out the flow of data from one function to the next, using variables as needed to hold intermediate results.
A few things I noticed from the code you showed (none of these are required to solve your immediate problem, but could be helpful now and in the future.):
Try to give your controls meaningful names. AggregatesButton, RangesButton, MeanLabel, etc are much easier to remember than Button1, Button2, etc. (There are various styles for names as well. Some people will use a prefix instead of a suffix for names like btnAggregates, btnRanges, lblMean.)
The numeric types all have a Shared Parse method. You may consider using this instead of the conversion as it allows you to specify several options about how to parse the number from a string. For now, the conversion will probably suffice, but this is at least something to tuck away for later.
I don't know what topics your class will cover later, but you may consider looking into the For Each loop instead of the standard For loop. This can be useful when you need to do something 'for each' item in a sequence but don't care about the index, such as the Mean, Range, StandardDeviation, and CountInRanges calculations. This can make your code cleaner because you won't keep referencing the array and makes it easier to convert to other sequence classes that you may run into later (eg: List, Collection, etc). It also keeps you from accidentally modifying the array, which you never want to do in any of those functions.

Appending text to a richTextBox in a different thread and code file

With the intention of creating a program to interface with a serial port device, I recently started learning vb.net. To keep the structure neat the vb code has been split into two places; the first is the code behind for initialising, clicking buttons etc., whilst the second is for managing the comm port. Respectively, these are named 'MainWindow.xaml.vb' and 'ComPortManager.vb'.
In 'comPortManager.vb':
Dim RXArray(2047) As Char ' Array to hold received characters
Dim RXCnt As Integer ' Received character count
Private Sub comPort_DataReceived(ByVal sender As Object, ByVal e As SerialDataReceivedEventArgs) Handles comPort.DataReceived
Do
RXCnt = 0
Do
'Populates the array, RXArray and counts the number of characters, RXCnt
Loop Until (comPort.BytesToRead = 0) 'Keeps reading the buffer until it is empty
'Code for posting to the richTextBox
Loop Until (comPort.BytesToRead = 0) 'If the buffer has been written to in the meantime, repeat
End Sub
The 'MainWindow.xaml' contains a ribbon (Microsoft's October 2010 release) with controls for settings, opening, closing and sending (keeping it all separate and simple for now), with the rest of the window being a richTextBox entitled 'RichTextBox1'.
The search for a way to post the contents of RXArray to RichTextBox1 brought up many suggestions based around Invoke or BeginInvoke. Indeed, working examples have been run successfully but all the code associated with Invoke has been in one file, the code behind. (Correct me if I'm wrong, but this sounds fine for small programs but could get bloated with medium to larger programs, hence me wanting to find a better solution)
The code closest to running (I believe) is as follows:
'In comPort_DataReceived... after populating the array
If RichTextBox1.InvokeRequired Then
RichTextBox1.Invoke(New MethodInvoker(AddressOf Display))
End If
'and back in the main code
Public Delegate Sub MethodInvoker()
Private Sub Display()
RichTextBox1.AppendText(New String(RXArray, 0, RXCnt))
End Sub
This has a few problems and I'm not sure in what direction to go at this stage. RichTextBox1 is in a different thread hence not recognised; InvokeRequired is not a member of System.Windows.Controls.RichTextBox, likewise with Invoke; and finally, in examples, the delegate entitled MethodInvoker was never stated as above.
Any help on this topic is most appreciated. In these few weeks, Invoke, BeginInvoke etc. have somewhat eluded my comprehension. Regards, Jonathan
we have a large scale application which a textbox has the status of many threads appended to it concurrently, and from different forms. this is a dumbed down version of it:
Public Sub addToMessageBox(ByVal msg As String)
If Me.InvokeRequired Then
Dim d As New AddToMessageBoxDelegate(AddressOf Me.addToMessageBox)
Me.BeginInvoke(d, New Object() {msg})
Else
Try
Me.MessageBox.AppendText("--" + msg + vbCrLf)
Catch ex As Exception
End Try
End If
End Sub
The delegate is declared at the begining
Private Delegate Sub AddToMessageBoxDelegate(ByVal msg As String)
the biggest difference that I can see is that I use the parent class's beginInvoke() and InvokeRequired(). I'd say give this a try. Call the parentClass.AddToMessageBox("Text you want to append") where you are calling the display().

Creating a control array in VB.NET

How can I make a control array? Or the equivalent.
I am used to Visual Basic 6 which presents the option of whether to create a control array when I copy and paste and control.
Control arrays are long gone. Object-oriented methods are now the law of the land for VB.
You need to use a collection of some sort, such as a list.
Another implicit feature of the control arrays that is easily overlooked is the association of numeric indexes with each element of the array. The indexes can be any positive int as long as they areunique in the collection; they do not have to be sequential. Consequently the array is more like a dictionary indexed by integers with each item value being an instance of a specific type of control.
Logic in the VB6 event handlers for the control array get the value of the index along with the attributes of the event to be handled. Logic in the handler typically uses the index to determine which instance of the control was raising the event.
.NET event handlers are quite different. You will typically get a reference to a specific control instance and an instance of a specific event object with the attributes of the event to be handled. You will NOT get the index.
Also, VB6 apps sometimes have logic that iterates/manipulates the control array as an array.
In our default translations, we try to support legacy VB6 logic that depends explicitly on the control array and its indexes. We rewrite control arrays as a group of individual control instances and then we add them to a generic OrderDictionary<int, controlType> during form initialization. The individual controls subscribe to the events and we can use the collection to lookup the index given a control instance or to iterate/manipulate the items in the "array". If you do not explicitly need the index or the array, you can get rid of the collection.
Dynamically adding controls is more work now -- it was conceptually like adding an item to the control array and supported with a single statement in VB6 (Load control). As far as I know, in .NET you need to clone a control, deep copy the properties explicitly, and hook up the event handlers explicitly. It can be generalized using reflection and other moderately advanced techniques -- but it sure is not simply calling "load control". If there is an easier way to do this in .NET I would love to hear about it. FWIW: we translate to a helper function.
A control array in VB6 solely existed to allow a single event handler for multiple controls of same type.
You do this in VB.NET by putting the controls into the Handles clause:
private sub Button_Click(...) Handles Command1.Click, Command2.Click, Command3.Click
end sub
You can act only through code. For example:
Dim c() As TextBox
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
Dim j As Integer
For j = 0 To 10
ReDim Preserve c(j)
c(j) = New TextBox
c(j).Name = "txt" & j
c(j).Parent = Me
c(j).Top = j * c(j).PreferredHeight + 2
c(j).Tag = j
c(j).Visible = True
AddHandler c(j).KeyPress, AddressOf TestKeyPress
Next
End Sub
Public Sub TestKeyPress(source As Object, e As KeyPressEventArgs)
Dim index As Integer
index = CInt(source.tag)
If index >= 5 Then
If e.KeyChar > "9" Or e.KeyChar < "0" Then
e.Handled = True
End If
Else
If e.KeyChar <= "9" And e.KeyChar >= "0" Then
e.Handled = True
End If
End If
End Sub
This will create eleven text boxes assigning to all the same event handler.
The TAG property is used to store and retrieve the idex of the text box.
there are three ways to create control array.
assign the same name to more then one control.
copy an evangelizing control and past it into the form.
set the index properly to a value that is not null.