delay or stop execution for some time in vb.net - vb.net

hi i want to delay the execution of code for some time on buton click i cal a func named chance() ..
which gets called after a picture box.image change .. bt the image does not change nd func chance() starts ... i want delay in chance() after the picture is changed ... thus help me ..
code
Private Sub p11_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles p11.Click
row = 1
col = 1
chck() 'function which returns hit var value
p11.Enabled = False
If hit = 1 Then
p11.Image = Image.FromFile("G:\visual progs\BATTLESHIP\hit.png")
ElseIf hit = 0 Then
p11.Image = Image.FromFile("G:\visual progs\BATTLESHIP\miss.png")
lblstatus.Text = "COMPUTER's TURN ... PLEASE WAIT ... "
chance() ' func begins
End If
End Sub
Function chance()
***'here i want a pause for 2 sec***
Dim z As Int16 = 1
While z = 1
row = mnw.Next(9) + 1
col = mnw.Next(9) + 1
If c(row, col) = False Then
c(row, col) = True
z = 0
End If
End While
chck1() ' checks for hit or miss for computer
changepic() 'changes pic hit or miss for computer
Return 0
End Function

To get a pause of 2 seconds, you simply need to suspend the thread by doing this:
Thread.Sleep(2000)

Although you can use Thread.Sleep to introduce a delay, it has generally undesirable side-effects, in particular the form and its controls become unresponsive. A better way is to use a timer - that way the form is still responsive (e.g. you can move it around).
Also, you seem to be a little unsure of where to use a Sub and where to use a Function. A Sub does something, and a Function is used to return a value, ideally with no side-effects.
You could try this with a new Windows Forms project and just a PictureBox named p11 and a Label named lblStatus:
Imports System.IO
Public Class Form1
Dim tim As Windows.Forms.Timer
Const GAMEPATH As String = "G:\visual progs\BATTLESHIP\"
Dim HitImgFile As String = Path.Combine(GAMEPATH, "hit.png")
Dim MissImgFile As String = Path.Combine(GAMEPATH, "miss.png")
Private Sub SetUpTimer()
tim = New Timer
tim.Interval = 2000 ' milliseconds
tim.Enabled = False
AddHandler tim.Tick, AddressOf Chance
End Sub
Private Sub Chance(sender As Object, e As EventArgs)
tim.Enabled = False
' your code for the computer's turn goes here
lblStatus.Text = "Your turn"
p11.Enabled = True
End Sub
Private Function IsHitByUser() As Boolean
' placeholder code for the actual check
If Rnd() < 0.5 Then
Return True
End If
Return False
End Function
Private Sub DoComputerTurn()
lblStatus.Text = "COMPUTER's TURN ... PLEASE WAIT ... "
p11.Enabled = False
tim.Enabled = True
End Sub
Private Sub p11_Click(sender As Object, e As EventArgs) Handles p11.Click
If IsHitByUser() Then
p11.Image = Image.FromFile(HitImgFile)
lblStatus.Text = "HIT"
Else
p11.Image = Image.FromFile(MissImgFile)
DoComputerTurn()
End If
End Sub
Private Sub StartGame()
lblStatus.Text = "Your turn"
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
SetUpTimer()
StartGame()
End Sub
End Class

Related

Refresh Chart Every Second

Have a question. I think it must be quite easy to implement but for some reason I can't do it. Right now the charts are updated if I click on them. I wish that they were updated every time I change a value (just like in Excel), for must be easier to implement a timer.
For some reason I can't implement it and I have already tried a few things that I have found online.
I have two charts and I want the charts to update the values every second (or the interval suitable for the program).
I am working on a Windows form and have the following VB code:
Private Sub Chart1_Click(sender As Object, e As EventArgs) Handles Chart1.MouseClick
AutoSize = False
Chart1.ChartAreas(0).AxisX.Interval = 0.05
Chart1.ChartAreas(0).AxisY.Interval = 200
With Chart1
.Series(0).Points.Clear()
.Series(1).Points.Clear()
.Series(2).Points.Clear()
End With
With Chart1
.Series(0).Points.AddXY(TOCGLong, TOSumMassValues)
.Series(1).Points.AddXY(LandCGLong, LandSumMassValues)
.Series(2).Points.AddXY(ZFWCGLong, ZFWSumMassValues)
End With
With Chart1.ChartAreas
With .Max
.AxisX.Maximum = 3.55
.AxisY.Maximum = 2300
End With
With .Min
.AxisX.Minimum = 3.15
.AxisY.Minimum = 1200
End With
End With
Chart1.Series(3).Points.Clear()
For i As Integer = 0 To 5
Chart1.Series(3).Points.AddXY(CGLimitX(i), CGLimitY(i))
Next
End Sub
Private Sub Chart3_Click(sender As Object, e As EventArgs) Handles Chart3.MouseClick
Dim FuelX() As Integer = {80, 90, 100, 110, 120, 130, 140, 150, 160, 170, 180}
Dim ISA() As Double = {27171.16, 24053.39, 21011, 18043.99, 15152.36, 12336.11, 9595.24, 6929.75, 4339.64, 1824.91, -614.44}
Dim ISA20() As Double = {25421.84, 21987.56, 18644, 15409.16, 12277.04, 9247.64, 6320.96, 3497, 775.76, -1842.76, -4358.56}
Dim ISA35() As Double = {23726.04, 19793.81, 16041, 12467.61, 9073.64, 5859.09, 2823.96, -31.75, -2708.04, -5204.91, -7522.36}
AutoSize = False
Chart3.ChartAreas(0).AxisX.Interval = 10
Chart3.ChartAreas(0).AxisY.Interval = 5000
With Chart3
.Series(0).Points.Clear()
'.Series(1).Points.Clear()
'.Series(2).Points.Clear()
End With
With Chart3
.Series(0).Points.AddXY(FuelConsuption, SDaltitude.Value)
For i As Integer = 0 To 10
.Series(1).Points.AddXY(FuelX(i), ISA(i))
.Series(2).Points.AddXY(FuelX(i), ISA20(i))
.Series(3).Points.AddXY(FuelX(i), ISA35(i))
Next
End With
With Chart3.ChartAreas
With .Max
.AxisX.Maximum = 180
.AxisY.Maximum = 23000
End With
With .Min
.AxisX.Minimum = 80
.AxisY.Minimum = 0
End With
End With
End Sub
Take the code out of the Chart1.MouseClick handler and put it in a Sub of its own with a descriptive name. Do the same for the Chart3.MouseClick handler.
In the Chart1.MouseClick handler, call that first Sub.
In the Chart3.MouseClick handler, call that second method.
For the question in the question:
I wish that they were updated everytime I change a value
In the appropriate textbox leave handlers, call the appropriate method(s), something like this:
Private Sub TextBox1_Leave(sender As Object, e As EventArgs) Handles TextBox1.Leave
UpdateChart1()
UpdateChart2()
End Sub
I suggest using the Leave event so that it doesn't keep changing while the user is in the middle of typing.
For the question in the title:
You should put the chart updating code in its own methods, as written above. Then you can easily call it from a timer's tick event. The essential parts of the code are like this:
Public Class Form1
Dim tim As Timer
Sub UpdateMpgChart()
' ... code here to update the chart
End Sub
Sub UpdateOtherChart()
' ... code here to update the other chart
End Sub
Sub TimerTickHandler(sender As Object, e As EventArgs)
UpdateMpgChart()
UpdateOtherChart()
End Sub
Sub InitialiseTimer()
tim = New Timer With {.Interval = 1000}
AddHandler tim.Tick, AddressOf TimerTickHandler
tim.Start()
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
InitialiseTimer()
End Sub
Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing
If tim IsNot Nothing Then
tim.Dispose()
End If
End Sub
End Class
I wish that they were updated every time I change a value (just like in Excel), for must be easier to implement a timer.
You can use the ReactiveProperty nuget.
You declare a ReactiveProperty for each value you want to "react":
public ReactiveProperty<int> Prop1 = new ReactiveProperty(0);
public ReactiveProperty<int> Prop2 = new ReactiveProperty(0);
In the constructor (or load event) just tell the property to update the chart:
Prop1.Subscribe(value => Chart1_Click(this, null));
Here I'm telling to Prop1 to execute the Chart1_Click method, but you can create an specific method for updating the charts and put this in the subscribe method instead the Chart1_Click.
And for change the Prop1 or Prop2 values just:
Prop1.Value = 5; // this line will run the specified method
Prop2.Value = 10;

Timer does not update labels

In a Windows Forms application, I've got a timer with the following code:
Public Class SyncForm
Public pbvalue As Integer = 0
Public pbProcess As String = ""
Sub DataProcess()
pb.Value += 1
pbProcess = "Read, match and compare"
...
pb.Value += 1
pbProcess = "Exporting..."
End Sub
Private Sub timerpb_Tick(sender As Object, e As EventArgs) Handles timerpb.Tick
pb.Value = pbValue
lbReadProcess.Text = pbProcess
lbReadProcess.Refresh()
pb.PerformStep()
End Sub
End Class
I start the DataProcess sub with a button on this form.
During the process, the progress bar is updated correctly, but the label on the form (lbReadProcess), that should indicate the currently running process, not. Can someone give me a hint, why not? Thanks.

Combo Box Returning -1 For SelectedIndex

I'm trying to pick up a combo box's selected index. This was working absolutely fine, then all of a sudden it started returning -1 no matter what item is selected
My code is:
Form Code
Private Sub Man_SelectedIndexChanged_1(sender As Object, e As EventArgs) Handles Man.SelectedIndexChanged, Units.SelectedIndexChanged
'Set Transducer Type
Call References.LevListAdd()
End Sub
References Module LevListAdd Sub
Public Sub LevListAdd()
Form1.Lev.Items.Clear()
If Form1.Man.Text = "Pulsar" Then
With Form1.Lev.Items
.Add("Ultra Range")
.Add("IMP Range")
.Add("Twin Range")
End With
End If
End Sub
This fills the combo box lev fine when the Man combo box item "Pulsar" is selected. I then want my users to click a button to generate some labels and stuff. The code is as such:
Button Click Code
Private Sub Generate_Click(sender As Object, e As EventArgs) Handles Generate.Click
If CheckGenerate() = False Then Exit Sub
Dim X = CheckGenerationType(Man.SelectedIndex, Lev.SelectedIndex, Level.Checked, Volume.Checked, ListBox1.SelectedIndex,
Units.SelectedIndex)
Call ParamPage(X)
End Sub
CheckGenerate simply checks that all boxes have been filled in. I pass the informtion from the form to the following function:
Public Function CheckGenerationType(Man As Integer, Lev As Integer, Level As Boolean, Volume As Boolean, TankType As Integer,
MeasurementUnit As Integer) As String
Dim M As Integer
Dim L As Integer
Dim CT As Integer
Dim TT As Integer
Dim Ms As Integer
M = Man
L = Lev
TT = TankType
Ms = MeasurementUnit
If Level = True Then
CT = 0
ElseIf Volume = True Then
CT = 1
End If
CheckGenerationType = CStr(M) + "." + CStr(L) + "." + CStr(CT) + "." + CStr(TT) + "." + CStr(Ms)
End Function
When the lev.selectedindex parameter arrives at this function, it reads -1. Even if the user has selected any of the 3 items. Can anyone explain why this is happening?
I've just tried your code. I get the same result (-1 in lev.SelectedIndex) and this was because jumped using tab through the controls my when i'm hitting the Man or Units Combobox it runs the LevListAdd() and then clears the Lev-ComboBox because of Form1.Lev.Items.Clear().
You should think about your call Man_SelectedIndexChanged_1 or maybe just use something like this:
Public Sub LevListAdd()
If Form1.Man.Text = "Pulsar" Then
Form1.Lev.Items.Clear()
instead of
Public Sub LevListAdd()
Form1.Lev.Items.Clear()
If Form1.Man.Text = "Pulsar" Then
And you should separate the calls from the man and unit ComboBoxes.
Private Sub Unit_SelectedIndexChanged_1(sender As Object, e As EventArgs) Handles Units.SelectedIndexChanged
' Do something
End Sub
Private Sub Man_SelectedIndexChanged_1(sender As Object, e As EventArgs) Handles Man.SelectedIndexChanged
Form1.Lev.Items.Clear()
Select Case Form1.Man.Text
Case "Pulsar"
With Form1.Lev.Items
.Add("Ultra Range")
.Add("IMP Range")
.Add("Twin Range")
End With
Case "animals"
With Form1.Lev.Items
.Add("dogs")
.Add("cats")
.Add("birds")
End With
End Select
End Sub

Is this program efficient

I've put together a small calculator application that works quite well, but despite being a novice to VB.net I know that the program probably isn't as efficient as it should be. The idea is that upon inputting numbers into a textbox and pressing a mathematical operator, the textbox will reset and continue the equation, storing the past values entered.
Dim input1 As Double
Dim numfunction As Double
'numerical functions (null = 0, add = 1, subtract = 2, divide = 3, multiply = 4)
Private Sub btnAdd_Click(sender As Object, e As RoutedEventArgs) Handles btnAdd.Click
If txtNum.Text = "" Then
MsgBox("Please enter a number")
Else
numfunction = 1
input1 = input1 + txtNum.Text
txtNum.Text = ""
End If
End Sub
Private Sub btnEqual_Click(sender As Object, e As RoutedEventArgs) Handles btnEqual.Click
If txtNum.Text = "" Then
MsgBox("Please enter a final number")
End If
If numfunction = 1 Then
txtNum.Text = txtNum.Text + input1
input1 = 0
End If
End Sub
Could you point me in the right direction as to what I should replace add or remove to make my programs more efficient in the future? Keep in mind that the BtnAdd_Click event is just one of 4 (add, sub, divide, multiply) and because of that btnEqual_Click will have a few if statements, checking for what function the user has put in, and if there is anything in txtNum at all.
Thanks in advance, I'm not asking for anyone to complete my code, but I'd love to see what options I have so I make more efficient programs in the future.
With a little initial effort you could simplify this task by using the power of object oriented programming:
Public Class Form1
' hold a reference to all operations in a list of operations
Private _operations As New List(Of Operation)
' the operation currently choosen
Private Property _currentOperation As Operation
' the 2 numbers you want to perform the operations on
Private _number1 As Double = 0
Private _number2 As Double = 0
Public Sub New()
InitializeComponent()
SetupOperations()
TextBox1.Text = 0
End Sub
Public Sub ChangeOperation(operation As Operation)
_number1 = _currentOperation.FunctionDelegate.Invoke(_number1, _number2)
TextBox1.Text = _number1
_currentOperation = operation
End Sub
Private Sub SetupOperations()
_operations.Add(New Operation(Me, btnAdd, Function(x, y)
Return x + y
End Function))
' heres the crux ... you use anonymous method to define your functions hook them to the form (Me) and the related Button
' all at once
' Similar for the other operations (subtract / multiply / divide / pow, and so on)
Dim equalsOperation As New Operation(Me, btnEqual, Function(x, y)
Return y
End Function)
_operations.Add(equalsOperation)
_currentOperation = equalsOperation
End Sub
' for this example i used only one textbox and a lable indicating wheter the number entered is a valid double
Private Sub TextBox1_TextChanged(sender As Object, e As EventArgs) Handles TextBox1.TextChanged
Dim result As Double
If Double.TryParse(TextBox1.Text, result) Then
_number2 = result
lblValid.Text = "Valid" ' tell the user that the number entered is valid or not
Else
lblValid.Text = "Invalid"
End If
End Sub
''' <summary>
''' An Operation that hooks up a button click and can execute the operation
''' </summary>
Public Class Operation
Private _owningForm As Form1
Public Property FunctionDelegate As Func(Of Double, Double, Double) ' use a delegate to a Func that returns double with 2 double parameters
Public Sub New(owningForm As Form1, boundButton As Button, functionDelegate As Func(Of Double, Double, Double))
Me.FunctionDelegate = functionDelegate
Me._owningForm = owningForm
AddHandler boundButton.Click, AddressOf boundButton_Click ' make the operation hook up on the click event
End Sub
Private Sub boundButton_Click()
_owningForm.ChangeOperation(Me)
End Sub
End Class
End Class
Hope this is not too confusing for you, I intended to show you a bigger world than simple routines and tons of eventhandlers
You could simplify your code by inserting your checking code into a separate subroutine.
Sub CheckVals()
If txtNum.Text = "" Then
MsgBox("Please enter a final number")
End If
If numfunction = 1 Then
txtNum.Text = txtNum.Text + input1
input1 = 0
End If
End Sub
You would then reference this sub from your two button click events.
Private Sub btnAdd_Click(sender As Object, e As RoutedEventArgs) Handles btnAdd.Click
CheckVals()
End Sub

Moving a form does not work

I would like to move my borderless form once a timer get's called, however, it is not doing anything. It also doesn't give an error. It just does nothing... Hope someone can help.
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
Debug.WriteLine("Timer has ticked. " & TimeOfDay)
Try
If Screen.AllScreens.Length = 2 Then
Debug.WriteLine("Screen is connected!")
Me.Location = New Point(Screen.AllScreens(1).Bounds.X, Screen.AllScreens(1).Bounds.Y)
Else
Debug.WriteLine("Screen is not connected!")
End If
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
Use this :
If Screen.AllScreens.Length > 1 Then
' To make it work with more than 2 screens (never tried though)
Dim SecondaryScreenIndex As Int32 = -1
' Find Secondary Screen...
' Because it happens AllScreens(0) is not always PrimaryScreen..?
For i As Int32 = 0 To Screen.AllScreens.Length - 1
If Screen.AllScreens(i) IsNot Screen.PrimaryScreen Then
SecondaryScreenIndex = i
Exit For
End If
Next
If SecondaryScreenIndex > -1 Then
Debug.WriteLine("Screen is connected!")
Me.Location = New Point( _
Screen.AllScreens(SecondaryScreenIndex ).Bounds.Left, _
Screen.AllScreens(SecondaryScreenIndex ).Bounds.Top)
' Try Left and Top if it makes any difference.
Else
Debug.WriteLine("Screen is not connected!")
End If
End If
The following is optional
.
(or garbage)
I would advise you to create a Class, like Screen_Class or ScreenTools with below content that handles the monitoring/checks on the available Screens if you plan to load more Forms...
' ...
Public Shared Event ScreensChanged() ' <- capture this event..
Private Shared ps_ScreensMonitor As System.Windows.Forms.Timer = Nothing
Private Shared ps_MonitorCount As Int32 = 0
Private Shared ps_PrimaryScreenIndex As Int32 = 0
Public Shared Sub BeginScreensMonitoring()
If ps_ScreensMonitor Is Nothing Then
ps_ScreensMonitor = New System.Windows.Forms.Timer()
ps_ScreensMonitor.Interval = 500
AddHandler ps_ScreensMonitor.Tick, AddressOf HandleScreensMonitoring
End If
If Not ps_ScreensMonitor.Enabled Then
ps_ScreensMonitor.Enabled = True
End If
End Sub
Public Shared Sub SuspendScreensMonitoring()
If ps_ScreensMonitor IsNot Nothing Then
ps_ScreensMonitor.Enabled = False
RemoveHandler ps_ScreensMonitor.Tick, AddressOf HandleScreensMonitoring
ps_ScreensMonitor.Dispose()
ps_ScreensMonitor = Nothing
End If
End Sub
Private Shared Sub HandleScreensMonitoring(sender As Object, e As System.EventArgs)
Dim i As Int32
Dim AnythingChanged As Boolean = False
' Locate PrimaryScreen...
For i = 0 To Screen.AllScreens.Length - 1
If Screen.AllScreens(i) Is Screen.PrimaryScreen Then
If ps_PrimaryScreenIndex <> i Then
ps_PrimaryScreenIndex = i
AnythingChanged = True
End If
Exit For
End If
Next
' Find if a screen has been connected or disconnected
If ps_MonitorCount <> Screen.AllScreens.Length Then
ps_MonitorCount = Screen.AllScreens.Length
AnythingChanged = True
End If
' Fire the event to notify the changes.
If AnythingChanged Then
RaiseEvent ScreensChanged
End If
End Sub
' WARNING !!! THIS IS NOT THREAD SAFE !
Then launch monitoring from your main Form constructor or Loading :
' ...
Screen_Class.BeginScreensMonitoring()
AddHandler Screen_Class.ScreensChanged, AddressOf HandleScreensUpdate
' ...
Private Sub HandleScreensUpdate()
' Do here whatever you want here...
' Get the index of the PrimaryScreen for example,
' (^^ you can also make a static ReadOnly PrimaryScreenIndex Property
' in the custom class above and even add a
' Static ReadOnly SecondaryScreenIndex if you want)
End Sub
Then you could control the loading of any form depending on the members you make available on this custom Class. Making this approach useable for your requirements depends on how you're using your forms...