What does this Do While Loop code do? - vb.net

I'm very new to Visual Basic and I'm having a hard time understanding "Do While" loops. The code I'm struggling with is below. Can someone walk me through what the code is doing? I understand the variables and assigning the label, I'm just not sure how to translate the loop.
Dim intSum As Integer
Dim intY As Integer
Do While intY < 3
For intX As Integer = 1 To 4
Next intX
intY += 1
Loop
lblSum.Text = intSum.ToString

Let's assume the example has simply been extracted from a larger program and the interesting bits of what the For loop and other stuff inside the While loop have been removed.
A Do While loop coded this way is similar to coding a For loop like:
For intY = 0 to 3
Next
But without actually specifying the starting condition for intY. It starts out as whatever value it has coming into the loop, which is sometimes handy.
The example doesn't modify intSum in any way, but I'm guessing that part of the code is just not included here.

Related

Reverse number array multiline textboxes

basically, I want to reverse the numbers. (in the textbox there will be only 2-digit numbers)
if I have Textbox1.text:
12
2
41
71
70
I want to display in the box (Textbox1.text)
21
2
14
17
70
Function:
Public Shared Function Reverse(num As Integer) As Integer
Dim _reverse As Integer = 0
While num <> 0
_reverse *= 10
_reverse += num Mod 10
num \= 10
End While
Return _reverse
End Function
it should work, it actually works, but I don't know how to arrange it to work in all lines.
For Each lines In TextBox1.Lines
Dim rev = Reverse(lines)
lines.Replace(lines, rev)
Next
This is a perfect example of what happens when people try to write code without knowing what the code is supposed to. What the code is supposed to do is not just the end result but the steps to get there. If you don't know what the steps are then you shouldn't be writing any code because it's unlikely that what you write will do anything useful. Code is simply an implementation of logic so you should be getting the logic down first. It doesn't take any programming experience to work out the logic because we could all do this if it was a manual process and that would be the same logic.
So, what are the steps involved?
Get the lines of the text.
Loop over the lines.
Reverse the current line.
Replace the original line with the result of reversing.
Replace the text with the complete results.
If you actually consider each of those steps, it should be obvious that you cannot use a For Each loop because that will only let you get data out of a list, not put data into it. That would make it obvious that a For loop is the right choice, because will let you get data out and put it in. Now you can write code that actually does something useful.
Dim lines = TextBox1.Lines
For i = 0 To lines.GetUpperBound(0)
Dim line = lines(i)
Dim number = CInt(line)
Dim result = Reverse(number)
lines(i) = result.ToString()
Next
TextBox1.Lines = lines
Simple stuff but, again, if you don't know what the code has to actually do, writing code to do it is a challenge. Always break the problem down into smaller parts first, so you can work on each part individually, and always work out the logic you're trying to implement - and test that logic manually - before trying to write code to implement it.

DataGridView Remove Error

I want to delete the duplicate value and blank lines in the DataGridView.
I am using the following code for this.
Private Sub dgwsil()
On Error Resume Next
For i2 As Integer = DataGridView1.RowCount - 1 To 0 Step -1
If Trim(DataGridView1.Rows(i2).Cells(0).Value.ToString()) = "" Then
DataGridView1.Rows.RemoveAt(i2)
End If
Next
Dim numberOfRows = DataGridView1.Rows.Count
Dim i As Integer = 0
While i < numberOfRows - 2
For ii As Integer = (numberOfRows - 1) To (i + 1) Step -1
If DataGridView1.Rows(i).Cells(0).Value.ToString() = DataGridView1.Rows(ii).Cells(0).Value.ToString() Then
DataGridView1.Rows.Remove(DataGridView1.Rows(ii))
numberOfRows -= 1
End If
Next
i += 1
End While
End Sub
Code sometimes works fine.
But sometimes it gives an error
How can I solve this problem ? Or is there any code you use for it?
It looks like you are going into this problem with a VBA mindset. In VBA, you would usually manipulate the datagridview directly and the On Error Resume Next line would be acceptable.
In VB.NET you don't want to do either of those things. Your datagridview should be bound to a collection of information. That collection can be a datatable or an array or any type of collection really. So instead of using a loop to manipulate the datagridview directly you would either loop through the backing collection or better yet LINQ through the collection and manipulate it however you need. There are a ton of tutorials out there explaining everything you could ever need so googling around for how to bind a datatable to a datagridview should get you what you need.
I would also suggest looking into the Try...Catch...Finally... structure. You should really use that to handle any errors that could possibly come up from your code.

Vb Guessing Game Random generator broken

In my code,I have now realised I have to use the New Random function, my code was working before with the Randomize and then the numbers but now it comes up with loads of errors and wont even let me run the program. I think it is only a small error but I just need some help to get the final bit going
Heres the code and thanks for any help :)
I cannot get the code to work with the randomly generated number and I have to use the New Random function I cannot use randomize() Does anybody know how to help here is the code.
Dim timestook As Int32 = 1
Dim usersguess As Integer
Dim value = New Random(0 - 19)
Console.WriteLine("You have to guess this number. It is between 1 and 20. Good Luck !")
usersguess = Console.ReadLine()
'keep looping until they get the right value
While usersguess <> value
'now check how it compares to the random value
If usersguess < value Then
timestook = timestook + 1
Console.WriteLine("You're too low. Go higher ")
ElseIf usersguess > value Then
Console.WriteLine("You're too high. Go Lower.")
timestook = timestook + 1
End If
'If they are wrong the code will run again,after telling the user if they are too high or too low.
usersguess = Console.ReadLine()
End While
' Console.WriteLine("You're correct. Well Done")
If usersguess = value Then
Console.WriteLine("You took,{0}", timestook)
End If
Console.ReadLine()
End Sub
You'll want to do some googling on how to use random numbers. Your problem is that you aren't creating a Random object to handle the random number generation.
Here's how you can fix your code:
Dim randNumGen As New Random() 'Create Random object
Dim value As Integer = randNumGen.Next(0, 20) 'set value equal to a new random number between 0-19
Please note that this code could be further refactored for readability and simplicity (like changing timestook = timestook + 1 to timestook += 1 and selecting better variable names like numberOfGuesses as opposed to timestook, etc.
The expression New Random(0-19) does not do at all what you think it does, name it does NOT return an integer. Instead, it creates an instance of a Random object, which is a type that knows how to create new random values. The 0-19 part of the expression is the seed for the Random object's constructor, and is the same as just passing the value -19.
This looks like it's either homework or personal practice, so I feel like you will be better served in this case with a separate example using the Random type for reference than you would if I fixed the code sample in the question for you:
Dim rnd As New Random()
For i As Integer = 0 To 10
Console.WriteLine(rnd.Next(0, 20))
Next i
It's also worth mentioning here that you typically only want one Random object for your entire program, or at least only one Random object for each logical part of your program. Creating new Random objects resets the seeds, and for best results you want to follow the same seed on subsequent calls to the same instance for a while.

VB.NET Is there a quicker way to scan through a RichTextBox?

I have a VB.NET application that I use to load various files into a RichTextBox and then scan through the document to find specific words. It's similar to the Find function in Word. The app was running fine until a 5,150 line .sql document run through it and it's taking upwards of 10 minutes to run to completion.
Can anyone recommend a better way of coding it than I have below?
If sqlText.Contains("GRANT") Then
Dim searchstring As String = "GRANT"
Dim count As New List(Of Integer)()
For i As Integer = 0 To rtbFile.Text.Length - 1
If rtbFile.Text.IndexOf(searchstring, i) <> -1 Then
count.Add(rtbFile.Text.IndexOf(searchstring, i))
End If
Next
Try
For i As Integer = 0 To count.Count - 1
rtbFile.Select(count(i), searchstring.Length)
rtbFile.SelectionBackColor = Color.Yellow
rtbFile.SelectionFont = New Font(rtbFile.Font, FontStyle.Bold)
count.RemoveAt(i)
Next
Catch ex As Exception
End Try
rtbFile.Select(rtbFile.Text.Length, 0)
rtbFile.SelectionBackColor = Color.White
rtbFile.SelectionFont = New Font(rtbFile.Font, FontStyle.Regular)
End If
That first loop is killing the performance, you are calling IndexOf for every character in the string. Also the two loops can be merged in to one. Change it to:
rtbFile.SelectionBackColor = Color.Yellow
rtbFile.SelectionFont = New Font(rtbFile.Font, FontStyle.Bold)
For Each m As Match in Regex.Matches(sertbFile.Text, searchstring)
rtbFile.Select(m.Index, searchstring.Length)
Next
This can also be done with a While loop and RichTextBox.Find():
Dim searchstring As String = "GRANT"
Dim index As Integer = rtbFile.Find(searchstring, 0, RichTextBoxFinds.None)
While index <> -1
rtbFile.Select(index, searchstring.Length)
rtbFile.SelectionBackColor = Color.Yellow
rtbFile.SelectionFont = New Font(rtbFile.Font, FontStyle.Bold)
index = rtbFile.Find(searchstring, index + searchstring.Length, RichTextBoxFinds.None)
End While
You've got a few bad things going on here:
First, the following code:
For i As Integer = 0 To rtbFile.Text.Length - 1
If rtbFile.Text.IndexOf(searchstring, i) <> -1 Then
count.Add(rtbFile.Text.IndexOf(searchstring, i))
End If
Next
This is looping through every character in your string, and calling IndexOf on the entire string from that point forward. So your 50,000-character string is running IndexOf 50,000 times, on large strings.
You only need to call IndexOf as many times as you find a string. When your string is found, you increment your start index to that point, and keep searching only from that point.
Next thing, this code:
For i As Integer = 0 To count.Count - 1
...
count.RemoveAt(i)
Next
The RemoveAt line is unnecessary. You're already looping through a list, so you don't need to remove the items as you go along. The way it stands, your loop will skip every other item in your list.
Whoops. I missed a very important point about the IndexOf (and incorrectly assumed it was fed with the end of the last match). See Magnus's answer.
I am not sure where the bottleneck is (and it might very well be from setting the selection itself), but here are my suggestions, roughly in order of priority:
Invoke rtbFile.Text once to avoid any roundtrips to underlying control (perhaps a native Windows control?) and use a variable to store the resulting string. Once the string is obtained in .NET, just keep using it directly unless/until the text may change. If the control is native then a lot of work may be required to simply "get the text".
Use normal item iteration over the count collection (not indexing) and do not remove from the front-of the List when assigning the selections. Removing from the front of a List is "expensive" in that it must shift all items down internally. Also, removing the element is unneeded here and dubious at best: since the collection being modified is also is being iterated which likely leads to incorrect behavior (skipped items), regardless of performance.
Only call IndexOf once per loop and use a variable to avoid a duplicate search. This likely won't have an overall impact, but it does avoid some "extra" work. IndexOf itself is fine and doesn't need to be replaced.
YMMV.

GetCrossReferenceItems in msword and VBA showing only limited content

I want to make a special list of figures with use of VBA and here I am using the function
myFigures = ActiveDocument.GetCrossReferenceItems(Referencetype:="Figure")
In my word document there are 20 figures, but myFigures only contains the first 10 figures (see my code below.).
I search the internet and found that others had the same problem, but I have not found any solutions.
My word is 2003 version
Please help me ....
Sub List()
Dim i As Long
Dim LowerValFig, UpperValFig As Integer
Dim myTables, myFigures as Variant
If ActiveDocument.Bookmarks.Count >= 1 Then
myFigures = ActiveDocument.GetCrossReferenceItems(Referencetype:="Figure")
' Test size...
LowerValFig = LBound(myFigures) 'Get the lower boundry number.
UpperValFig = UBound(myFigures) 'Get the upper boundry number
' Do something ....
For i = LBound(myFigures) To UBound(myFigures) ‘ should be 1…20, but is onlu 1…10
'Do something ....
Next i
End If
MsgBox ("Done ....")
End Sub*
Definitely something flaky with that. If I run the following code on a document that contains 32 Figure captions, the message boxes both display 32. However, if I uncomment the For Next loop, they only display 12 and the iteration ceases after the 12th item.
Dim i As Long
Dim myFigures As Variant
myFigures = ActiveDocument.GetCrossReferenceItems("Figure")
MsgBox myFigures(UBound(myFigures))
MsgBox UBound(myFigures)
'For i = 1 To UBound(myFigures)
' MsgBox myFigures(i)
'Next i
I had the same problem with my custom cross-refference dialog and solved it by invoking the dialog after each command ActiveDocument.GetCrossReferenceItems(YourCaptionName).
So you type:
varRefItemsFigure1 = ActiveDocument.GetCrossReferenceItems(g_strCaptionLabelFigure1)
For k = 1 To UBound(varRefItemsFigure1)
frmBwtRefDialog.ListBoxFigures.AddItem varRefItemsFigure1(k)
Next
and then:
frmBwtRefDialog.Show vbModeless
Thus the dialog invoked several times instead of one, but it works fast and don't do any trouble. I used this for one year and didn't see any errors.
Enjoy!
Frankly I feel bad about calling this an "answer", but here's what I did in the same situation. It would appear that entering the debugger and stepping through the GetCrossReferenceItems always returns the correct value. Inspired by this I tried various ways of giving control back to Word (DoEvents; running next segment using Application.OnTime) but to no avail. Eventually the only thing I found that worked was to invoke the debugger between assignments, so I have:
availRefs =
ActiveDocument.GetCrossReferenceItems(wdRefTypeNumberedItem):Stop
availTables =
ActiveDocument.GetCrossReferenceItems(wdCaptionTable):Stop
availFigures = ActiveDocument.GetCrossReferenceItems(wdCaptionFigure)
It's not pretty but, as I'm the only person who'll be running this, it kind of works for my purposes.