Label.Text doesn't change in a loop - vb.net

I'm trying to change a text that a label displays during each iteration of a Do While loop in Visual Basic. One label (which displays an integer) works fine, however the other stays blank until the loop finishes and displays the final result. What could be the problem?
Private Sub btnCalc_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
Handles btnOblicz.Click
Dim W As Single
Dim L As Integer
Dim J As Integer
Dim Y As Double
W = Val(txtW.Text)
L = InputBox("Input L")
J = 0
If W > 0 And W < 100 Then
Do
Y = (2 * Math.Sqrt(W)) / (L - J)
J = J + 1
lblJ.Text = Str(J)
lblY.Text = Str(Y)
MsgBox("Next...")
Loop Until Y < 0
Else
MsgBox("No calculations, because the number is less than zero or greater than a hundred.")
End If
End Sub

Application.DoEvents(), as suggested by others, can work. However, you should be aware that it has some negative side-effects, such as the potential to create StackOverflowExceptions.
The right way to solve this problem is to use a BackgroundWorker component.
As to why this happens... remember that all windows programs work by having, at their core, a loop which checks for messages from the user and operating system (things like mousemove events, clicks, keystrokes, etc). When you set the text property of a label, you are not telling the label to re-draw itself on the screen. Instead, you are posting an event to the operating system that your program's message loop must then receive and process. As new events come in, the message loop (or pump) sends those events to the proper method.
Your btnCalc_Click() function is one such method. If your function is running, it was called by the core windows messaging loop, which is now waiting for your method to complete and return control: it's blocked. The loop cannot continue receiving and dispatching methods until your function completes, and therefore nothing in your program's interface can be updated.

This worked fine for me in small copy I did using VS2010
It may be that a message pump is required. Try this :
System.Windows.Forms.Application.DoEvents()

Probably, your window function which processes OS event message is inaccesible while your loop executes. Try explicitly call dispatching messages. E.g. insert after assigning labels text inside your loop
Application.DoEvents

Related

In Visual Basic 2022, can I interrupt a panel.Refresh() in the middle of plotting on the panel?

I am plotting a Julia Set in a panel named pnlGraph that is 601 x 601 pixels. I determine the color of each pixel in a Paint event, and plot the entire Set using the command pnlGraph.Refresh(). It takes the PC about a minute to plot all 361,201 pixels. If I see an error early in the process of the panel refreshing, I would like to be able to interrupt the refresh and do something else.
I have searched the internet and found something called DoEvents() that I am unable to use properly. Can anyone help me use DoEvents() or some other method to interrupt a panel in mid-refresh in order to save time? Thank you.
#Jimi's suggestion to use a bitmap instead of the paint event worked wonders, cutting down the time to display the image by over 80%. If I use fewer iterations, the bitmap appears almost instantaneously. That means I don't have to wait over a minute to display each image, which solves my problem.
Here's the code I developed in a separate project to create the bitmap. It's more complicated in the program I wanted it for, but this cuts out all the code that is not needed to solve my problem. I deleted the Panel and replaced it with a PictureBox called pbxFractal. That's where I placed the bitmap image. Very cool stuff.
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
Dim i, j, i1, j1 As Int16
Dim fractalBitmap As Bitmap = New Bitmap(601, 601)
Dim pixColor As Color
For i = 0 To 600
For j = 0 To 600
i1 = i Mod 256
j1 = j Mod 256
pixColor = Color.FromArgb(255, i1, j1, Math.Abs(i1 - j1))
fractalBitmap.SetPixel(i, j, pixColor)
Next j
Next i
pbxFractal.Image = fractalBitmap
End Sub

Visual Basic: Image moves up and and then back down after a button click

I am attempting to make a character appear to jump straight up in the air and then come back down and return to the same level he started at. (y=100) The code below seems to make the program fight itself and move him up and down at the same time.
I have tried countless methods and all of them resulted in the guy either going up and not coming back down or flying off the page.
Private Sub btnJump_Click(sender As Object, e As EventArgs) Handles btnJump.Click
tmrJump.Start()
End Sub
Private Sub tmrJump_Tick(sender As Object, e As EventArgs) Handles tmrJump.Tick
For intCounterUp As Integer = 100 To 15
picSpaceRunner.Location = New Point(intCounterX, intCounterY)
intCounterY = intCounterUp
Next intCounterUp
For intCounterDown As Integer = 15 To 100
picSpaceRunner.Location = New Point(intCounterX, intCounterY)
intCounterY = intCounterDown
Next intCounterDown
End Sub
End Class
The code is running with no delay, so you're at the mercy of the machine.
I'm not a professional game coder, so I couldn't explain the intricacies of modern game engines. However, one of the basic ideas I learned a long time ago is to control your game/animation loop. Consider the frames per second.
In your code, it could be as simple as adding a delay within each loop iteration. If you want the character to complete his jump in 2 seconds (1 second up, 1 second down), then divide 1000 (1 sec = 1000 ms) by the number of iterations in each loop and delay by that amount. For example, you have 85 iterations, so each iteration would take approximately 12 ms.
If you don't mind blocking a thread, you can do this very easily with Threading.Thread.Sleep(12). If blocking is an issue, you'll likely want to use an external timer.
I found this link during a Google search. He explains how to set up a managed game loop in VB.Net.
http://www.vbforums.com/showthread.php?737805-Vb-Net-Managed-Game-Loop
UPDATE: Per OP's comment...
To do this using timers, you'll want to manipulate the character object directly within the Timer event handler (Tick). You wouldn't use loops at all.
Set the Timer's Interval to the value discussed earlier - the number of ms corresponding to how long it takes to move 1 pixel. Then, in the Timer's Tick handler, set the character object's Location equal to a new Point with the new value. Also in the Tick handler, check your upper bound (15), then reverse the process until it hits the lower bound (100).
For example,
Private Sub tmrJump_Tick(sender As Object, e As EventArgs) Handles tmrJump.Tick
If (intCounterY > 15 And blnGoingUp == True) Then
picSpaceRunner.Location = new Point(intCounterX, intCounterY - 1);
End If
... Remaining Code Goes Here ...
End Sub
Do not put the loop in the timer_tick. Increase or decrease the height by set interval instead and then check if the image had reached the maximum or minimum height.

Multithreading in vb.net to simulate task

I have a program that is doing one task.
For Example i have one list box containing some links.
And on the other hand my program is opening them one by one but i want it to be done faster
i have used for-each loop for that purpose.
All what i want to do is i wanna give every 2 or 3 link to a different thread or if there is any other solution to make it Faster Kindly tell me.
This is a small piece of code from my program.
For value As Integer = 1 To TextBox1.Text
If (value = TextBox1.Text) Then
Exit For
End If
Dim page As String = "-p-" & value
Extractor.ScrapLinks(txturl.Text + page, lstbox)
lbllinks.Text = lstbox.Items.Count
Next
I don't know what Extractor.ScrapLinks actually do, but it seems that you need to access UI thread and you cannot create multiple UI threads so eventually you will process them sequentially
What you can do to improve the solution is to read the data you want from the UI controls and then process that data on a separate thread, after completion you can fill the results into the UI by invoking some method on the UI thread as shown below
Delegate Sub PerformOperationDel(value As Integer)
Sub PerformOperation(value As Integer)
Dim page As String = "-p-" & value
Extractor.ScrapLinks(txturl.Text + page, lstbox)
lbllinks.Text = lstbox.Items.Count
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
For value As Integer = 1 To CInt(TextBox1.Text) - 1
lstbox.BeginInvoke(New PerformOperationDel(AddressOf PerformOperation))
Next
End Sub
You can use backgroundworkers but notice that you cannot access UI controls in the DoWork but you can access them on work completed (Refer to: Background worker proper way to access UI)
Best of luck

Replacing my function with a better one

i'm trying to popup a msgbox everytime the current time is equal to a field in a table in the database i'm using the following code:
For i As Integer = 0 To contentTable.Rows.Count() - 1
UpdateListBoxRec2("Sending content " & i + 1 & " to :")
For j As Integer = 0 To subTable.Rows.Count() - 1
While send = False
If contentTable.Rows(i).Item(1) = DateTime.Now.ToString("hh:mm") Then
UpdateListBoxRec2(subTable.Rows(j).Item(0))
MsgBox(contentTable.Rows(i).Item(0))
send = True
End If
End While
'send = False
Next
Next
this method works but when the debugger is in the while loop ( means when the current time is not yet equal to the time i have in my db table ) i can't use any tool of my windows app untill the debugger gets out of the while loop so i'm searching for a similar method to popup my msgbox in the same condition and to be able to use my tools in the app all the time
please note that i'm using vb.net
any help please :)
You should never sit in an endless loop, like that, on the UI thread. As long as the UI thread is busy, it will be blocked from processing any incoming window messages (e.g. key strokes, mouse clicks). You could sit in a loop like that if you were on a separate thread, but that would be silly. The more sane solution would be to use a timer. For instance, if you drop a Timer component onto your form in the designer, and set it's Interval property to 5000 (five seconds), you can then add the following code:
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
For i ...
For j ...
If contentTable.Rows(i).Item(1) = DateTime.Now.ToString("hh:mm") Then
UpdateListBoxRec2(subTable.Rows(j).Item(0))
MessageBox.Show(contentTable.Rows(i).Item(0))
End If
Next
Next
End Sub
Now it will just run that code once every five seconds rather than continuously checking the current time and thereby hogging the UI thread.

Visual basic 2008 issue with adding a method to my dynamic objects

I have searched for an answer to my question since last thursday. A lot of answers about my exact same question have been answerd in vb.net. However, I am working on Visual Basic 2008 and those two language seems to have differences that are for me difficult to understand. So here is my issue.
I need to create several picture box and I have created them dynamicly as several sites recommanded. That part works fine. Issue begins when I want to click on them. I read enough to understant that it is not because I have created the object that I have created the method attached to them. Then I create the method. Still no problem except when I am running the code each button does the same thing because they are all attached to the same method. I came to a solution: I need to transfer with the method an argument to tell wich Picturebox I am clicking on, but because I am using addressof I can't. I know few sites that have talked about the same issues and solved it using a lamda expression. If someone could give me the code I should use I would be really thankful.
Here is my code:
For i = 0 To 7
'couleur is the name I give to my picturebox object and objet () is the sub in which I created my object
couleur(i) = objet()
Next
For x = 0 To 7
' initiasation of location, etc.
Next
' This is the issue !!! I do not know how to say this line into vb8
' I want to pass in argument X to know on which object I have cliked on and then use a seled case to make separated command afterward.
For x = 0 To 7
AddHandler couleur(i).Click, Function(senderobj, args) couleur_click(x)
Next
End Sub
Sub couleur_click(ByVal i As Integer)
' select case doing seperated things depending on the x receive in argument
End Sub
Thank all of you for help, sorry for my language it is not my first language.
Why don't you change couleur_click to take the sender as a parameter? You will then know the source of the click, from which you can find the index of the PictureBox in your couleur array:
' ...
For x = 0 To 7
AddHandler couleur(i).Click, AddressOf couleur_click
Next
' ...
Sub couleur_click(sender As Object, e As EventArgs)
Dim pictureBoxSource As PictureBox = sender
' Find the index of the source in the base collection
Dim index = Array.IndexOf(couleur, pictureBoxSource)
Select Case index
' ...
End Select
End Sub
Set the tag property of each PictureBox, then in the click event handler you can do a select case on the tag.
You can't add parameters to the built in event handlers.