How to pause an animation inside a loop without delay - vb.net

I am having an issue with this piece of code:
Do While StopProgram = False
Do Until Count = v
Application.DoEvents()
Do While StopProgram = False
If DirectionNegative = False Then
Me.Refresh()
Count += 1
Angle += 1
RadianAngle = Angle * PlaceHolder
If Angle >= 51 Then
Angle = 49
DirectionNegative = True
End If
ElseIf DirectionNegative = True Then
Me.Refresh()
Count += 1
Angle -= 1
RadianAngle = Angle * PlaceHolder
If Angle <= -51 Then
Angle = -49
DirectionNegative = False
End If
End If
Loop
Loop
Count = 0
Loop
The problem is that when I press a button on my form, stopping the code (Using the StopProgram = False), it will continue until Count = v I want to be able to have it where I can stop it inside the loop, I have attempted to do that here but it creates an unexitable loop which ruins the program.

Better yet, use a Timer to tick at regular intervals.
http://msdn.microsoft.com/en-us/library/system.timers.timer(v=vs.110).aspx?cs-save-lang=1&cs-lang=vb#code-snippet-2
Dim WithEvents t as New System.Timers.Timer
sub t_Elapsed Handles....
'your code here. increment/decrement state variables
end sub
Simply disable the timer when you want animation to stop.

This is the wrong approach to your problem, but change:
Do While StopProgram = False
Do Until Count = v
Application.DoEvents()
Do While StopProgram = False
To:
Do While StopProgram = False
Do Until Count = v
Do While StopProgram = False
Application.DoEvents()

This should work just fine. No need for all those loops.
Public Sub Refresh()
' ...
End Sub
Public Property Get StopProgram() As Boolean
StopProgram = ' ...
End Property
Public Property Get Angle as Single
'...
Public Property Let Angle
'...
Public Property Get RadianAngle as Single
RadianAngle = Angle * PlaceHolder
End Property
Public Sub T()
Dim Step As Single
Step = 1!
Do
DoEvents
Me.Refresh
If StopProgram Then Exit Do
If Angle <= 0 Or Angle >= 50 Then
Step = -Step
End If
Count = Count + 1
Angle = Angle + Step
Loop
End Sub

You could just remove the 2 outer loops.
You will never reach the Do Until Count = v part unless StopProgram is true anyway.
You will remain inside the inner Do While StopProgram = False loop. You could remove
the inner Do While StopProgram = False loop and change
Do Until Count = v to Do Until Count = v Or StopProgram = true
btw you're setting Count = 0 when you exit the middle loop so if you need to retain the value of count when StopProgram is set to true you should remove the outer
Do While StopProgram = False loopand the Count = 0
Do Until Count = v Or StopProgram = True
Application.DoEvents()
If DirectionNegative = False Then
Me.Refresh()
Count += 1
Angle += 1
RadianAngle = Angle * PlaceHolder
If Angle >= 51 Then
Angle = 49
DirectionNegative = True
End If
ElseIf DirectionNegative = True Then
Me.Refresh()
Count += 1
Angle -= 1
RadianAngle = Angle * PlaceHolder
If Angle <= -51 Then
Angle = -49
DirectionNegative = False
End If
End If
Loop

Related

Animation of shapes in Visio via VBA

Is it possible to, f.ex., rotate shapes or change different (boolean) settings like visibilty by giving commands via the object's ID or is prior selecting necessary?
As far as I got it, I have to select an deselect each item prior to change its characteristics/ data.
My code looks like this (shall produce an "animation" of blinking arrows):
Private Sub timeout(duration_ms As Double)
Start_Time = Timer
Do
DoEvents
Loop Until (Timer - Start_Time) >= duration_ms
End Sub
Private Sub cmd_blinking_Click()
rep_count = 0
Target = 400
blink = 0.3
Do Until rep_count = Target
DoEvents
rep_count = rep_count + 1
ActiveWindow.Select Application.ActiveWindow.Page.Shapes.ItemFromID(255), visSelect
Application.ActiveWindow.Selection.Visible = True
ActiveWindow.DeselectAll
ActiveWindow.Select Application.ActiveWindow.Page.Shapes.ItemFromID(256), visSelect
Application.ActiveWindow.Selection.Visible = False
ActiveWindow.DeselectAll
ActiveWindow.Select Application.ActiveWindow.Page.Shapes.ItemFromID(257), visSelect
Application.ActiveWindow.Selection.Visible = False
ActiveWindow.DeselectAll
timeout (blink)
ActiveWindow.Select Application.ActiveWindow.Page.Shapes.ItemFromID(256), visSelect
Application.ActiveWindow.Selection.Visible = True
ActiveWindow.DeselectAll
timeout (blink)
ActiveWindow.Select Application.ActiveWindow.Page.Shapes.ItemFromID(257), visSelect
Application.ActiveWindow.Selection.Visible = True
ActiveWindow.DeselectAll
timeout (blink*3)
ActiveWindow.Select Application.ActiveWindow.Page.Shapes.ItemFromID(255,256,257), visSelect
Application.ActiveWindow.Selection.Visible = False
ActiveWindow.DeselectAll
timeout (blink * 0.9)
Loop
End Sub
Easier way I am looking for if possible:
Private Sub timeout(duration_ms As Double)
Start_Time = Timer
Do
DoEvents
Loop Until (Timer - Start_Time) >= duration_ms
End Sub
Private Sub cmd_blinking_Click()
rep_count = 0
Target = 400
blink = 0.3
Do Until rep_count = Target
DoEvents
rep_count = rep_count + 1
ActiveWindow.Shapes.ID(255).Visible = True
ActiveWindow.Shapes.ID(256).Visible = False
ActiveWindow.Shapes.ID(257).Visible = False
timeout (blink)
ActiveWindow.Shapes.ID(256).Visible = True
timeout (blink)
ActiveWindow.Shapes.ID(257).Visible = False
timeout (blink * 3)
ActiveWindow.Shapes.ID(255).Visible = False
ActiveWindow.Shapes.ID(256).Visible = False
ActiveWindow.Shapes.ID(257).Visible = False
timeout (blink * 0.9)
Loop
End Sub
For anyone looking for "animated arrows" in VBA (as I was asking):
The function is for making a pause in between the appearance of the individual objects / shapes.
Afterwards the objects/shapes need to change their Visibility property to make an "blinking effect".
In my example I used three arrows with specific given names ("Left_Arrow_1", etc.), here the object names must be inserted. By making a macro for inserting objects an giving them defined names, this is making things easier.
Sub timeout(duration_ms As Double)
Start_Time = Timer
Do
DoEvents
Loop Until (Timer - Start_Time) >= duration_ms
End Sub
Sub blinking_arrows()
rep_count = 0
target = 400
blink = 0.3
Do Until rep_count = target
DoEvents
rep_count = rep_count + 1
Sheet1.Shapes("Left_Arrow_1").Visible = True
Sheet1.Shapes("Left_Arrow_2").Visible = False
Sheet1.Shapes("Left_Arrow_3").Visible = False
timeout (blink)
Sheet1.Shapes("Left_Arrow_2").Visible = True
timeout (blink)
Sheet1.Shapes("Left_Arrow_3").Visible = True
timeout (blink * 3)
Sheet1.Shapes("Left_Arrow_1").Visible = False
Sheet1.Shapes("Left_Arrow_2").Visible = False
Sheet1.Shapes("Left_Arrow_3").Visible = False
timeout (blink * 0.9)
Loop
End Sub

Scroll bar for line graph VB.NET

I created a line graph in Visual Basic to show how many calories the user eats per day. However, my user requires me to include a scroll bar to scroll back and forward along the x-axis to view more days.
Unfortunately, I have never done anything like this before, and after looking through Stack Overflow and Googling, I cannot see any examples of anyone doing so.
Here is a screenshot of my graph so far:
And here is the code:
Cursor.Current = Cursors.WaitCursor
CalorieChartView = True
BurntChartView = False
NetChartView = False
Dim Series As Series = CalorieChart.Series(0)
'keeps track of if the chart is empty, starting as true
Dim empty As Boolean = True
'Clears the chart
Series.Points.Clear()
'Draws the chart in dark red
Series.Color = Color.DarkRed
'The legend text is changed
Series.LegendText = "Calories Consumed"
'For each of the past 8 days, a point is plotted with how many calories were eaten in that day
For i = -7 To 0
Series.Points.Add(User.GetCaloriesEaten(User.Username, Date.Now.AddDays(i)))
Series.Points(7 + i).AxisLabel = Date.Now.AddDays(i).ToString("dd/MM/yyyy")
'If any of the points are not 0
If User.GetCaloriesEaten(User.Username, Date.Now.AddDays(i)) <> 0 Then
'the chart is not empty
empty = False
End If
Next
HandleEmpty(empty)
Cursor.Current = Cursors.Default
I would appreciate any help.
If I understand your question you want to add a horizontal scroll bar to your graph. I have made some modification and new code to your code as for mock data purpose. Please refer the below code. You can get the idea by running this code separately.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim blockSize As Integer = 10
Cursor.Current = Cursors.WaitCursor
CalorieChartView = True
BurntChartView = False
NetChartView = False
CalorieChart.Series.Clear()
Dim series = CalorieChart.Series.Add("My Series")
series.ChartType = SeriesChartType.Line
series.XValueType = ChartValueType.Int32
'keeps track of if the chart is empty, starting as true
Dim empty As Boolean = True
'Clears the chart
series.Points.Clear()
'Draws the chart in dark red
series.Color = Color.DarkRed
'The legend text is changed
series.LegendText = "Calories Consumed"
'For each of the past 8 days, a point is plotted with how many calories were eaten in that day
Dim sizeOfDayToDisplay As Int16 = 0
For i = 0 To 100
'Series.Points.Add(User.GetCaloriesEaten(User.Username, Date.Now.AddDays(i)))
'Series.Points(7 + i).AxisLabel = Date.Now.AddDays(i).ToString("dd/MM/yyyy")
''If any of the points are not 0
'If User.GetCaloriesEaten(User.Username, Date.Now.AddDays(i)) <> 0 Then
' 'the chart is not empty
' empty = False
'End If
' just for testing purpose.
series.Points.Add(getRandumNumber())
series.Points(i).AxisLabel = Date.Now.AddDays(i).ToString("dd/MM/yyyy")
' series.Points.AddXY(i, Date.Now.AddDays(i).ToString("dd/MM/yyyy"))
sizeOfDayToDisplay += 1
Next
'most new code added is below here
Dim chartArea = CalorieChart.ChartAreas(Series.ChartArea)
chartArea.AxisX.Minimum = 0
chartArea.AxisX.Maximum = sizeOfDayToDisplay
chartArea.CursorX.AutoScroll = True
chartArea.AxisX.ScaleView.Zoomable = True
chartArea.AxisX.ScaleView.SizeType = DateTimeIntervalType.Number
Dim position As Integer = 0
Dim size As Integer = blockSize
chartArea.AxisX.ScaleView.Zoom(position, size)
chartArea.AxisX.ScrollBar.ButtonStyle = ScrollBarButtonStyles.SmallScroll
chartArea.AxisX.ScaleView.SmallScrollSize = blockSize
'HandleEmpty(empty)
'Cursor.Current = Cursors.Default
End Sub
Public Function getRandumNumber() As Int16
Return CInt(Math.Floor((3500 - 1000 + 1) * Rnd())) + 1000
End Function
Based on this: How to scroll MS Chart along x-axis in vb.net, you can use:
Chart1.Series("LoadCell").Points.AddY(receivedData)
Chart1.ResetAutoValues()
If Chart1.Series("LoadCell").Points.Count >= 100 Then
Chart1.Series("LoadCell").Points.RemoveAt(0)
End If
It Auto scales the y axis as well as limiting the x axis to 100 by
removing the first entry when the entries exeed 100.

Why do I get an overflow / #INF error, when attempting to position chart label?

I have the following procedure, which I use to add labels to a chart:
Sub add_comments(apply_to As Series, source_range As Range)
Dim i As Long
Dim c As Range
If source_range.Count > apply_to.Points.Count Then
Set source_range = source_range.Resize(apply_to.Points.Count, 1)
End If
i = 1
For Each c In source_range
If Not IsError(c) And i <= apply_to.Points.Count Then
If Len(c.Text) <> 0 Then
apply_to.Points(i).HasDataLabel = True
apply_to.Points(i).DataLabel.Text = c.Value2
apply_to.Points(i).DataLabel.Format.AutoShapeType = msoShapeRectangle
With apply_to.Points(i).DataLabel.Format.Line
.Visible = msoTrue
.ForeColor.RGB = RGB(0, 0, 0)
End With
apply_to.Points(i).DataLabel.Position = xlLabelPositionAbove
Debug.Print apply_to.Points(i).DataLabel.Top
apply_to.Points(i).DataLabel.Top = apply_to.Points(i).DataLabel.Top - (10 + apply_to.Points(i).DataLabel.Height)
Else
If apply_to.Points(i).HasDataLabel Then
apply_to.Points(i).DataLabel.Delete
End If
End If
End If
i = i + 1
Next c
apply_to.HasLeaderLines = True
End Sub
However, when I run the sub, it aborts on the line apply_to.Points(i).DataLabel.Top = apply_to.Points(i).DataLabel.Top - (10 + apply_to.Points(i).DataLabel.Height) with an overflow error. Trying to print the value of apply_to.Points(i).DataLabel.Top makes it seem like there is a problem with fetching the top value of the datalabel:
However, looking at the graph, the label seems to have a valid position, and should have a .Top value.
Can someone give me a pointer to what is going wrong in my procedure, please?

How to compare between two images using VB.net?

I have a small bitmap image and I will do a screenshot. I need to find whether the small image is the screenshot. How I can compare two bitmap images? and then return the coordinates.
If it is MATLAB, (NOTE: I need VB.net)
What my plan is this
screenshot
for x_screen = 1: screen_width_x
for y_screen = 1: screen_col_y
for x_pic = = 1: pic_width_x
for y_pic = = 1: pic_col_y
if screenshot(x_screen, y_screen) != pic(x_pic , y_pic)
break
end
end
xx = (x_screen)
yy = (y_screen)
end
end
See Image comparison if you want something advanced Also you can look for machine learning techniques for such tasks.
Here is naive solution and not optimized one (plus it is better to do such tasks in native code):
Plus Note that it is better to check this with bmp files. otherwise it will not handle problem
Private Function FindSubImg2(img As Bitmap, subimg As Bitmap) As Point
If (img.Width - subimg.Width < 0) Or (img.Height - subimg.Height < 0) Then Return Nothing
Dim stepxLen As Integer = img.Width - subimg.Width
Dim stepyLen As Integer = img.Height - subimg.Height
Dim coor As Point
Dim match As Boolean = False
For oy As Integer = 0 To stepyLen
For ox As Integer = 0 To stepxLen
match = True
For x As Integer = 0 To subimg.Width - 1
For y As Integer = 0 To subimg.Height - 1
'actually here we do not need ToArgb method. But it will skip unneeded Color comparisions
If img.GetPixel(x + ox, y + oy).ToArgb <> subimg.GetPixel(x, y).ToArgb Then
match = False
Exit For 'we can use goto operator instead of double exit for
End If
Next
If match = False Then Exit For
Next
If match = True Then
coor.X = ox
coor.Y = oy
Return coor
End If
Next
Next
Return New Point(-1, -1)
End Function
Private Function FindSubImg(a As Bitmap, b As Bitmap) As Point
Dim subimg As Bitmap
Dim img As Bitmap
If (a.Height <= b.Height AndAlso a.Width <= b.Width) Then
subimg = a : img = b
Return FindSubImg2(img, subimg)
ElseIf (a.Height > b.Height AndAlso a.Width > b.Width) Then
subimg = b : img = a
Return FindSubImg2(img, subimg)
Else
Return New Point(-1, -1)
End If
End Function
Usage:
Dim p As Point = FindSubImg(New Bitmap("A.bmp"), New Bitmap("B.bmp"))
Try something like this:
Public Function CompareImages(ByVal img1 As Bitmap, ByVal img2 As Bitmap) As Boolean
Dim i As Integer
Dim j As Integer
For i = 0 To img1.Width - 1
For j = 0 To img2.Height - 1
If img1.GetPixel(i, j) <> img2.GetPixel(i, j) Then
Return False
End If
Next
Next
Return True
End Function
sample call:
CompareImages(New Bitmap("f:\img1.bmp"), New Bitmap("f:\img2.bmp"))

What else can cause an AxWindowsMediaPlayer to play?

I have a button in my program that grabs a bunch of information from a DataGridView object (volume, url, delay, etc) and using that, it plays a file. I'm trying to get the delay to work (wait x number of seconds before playing) and I'm pretty it will work, but whenever I press the button, the play starts immediately. There is no Ctlcontrols.play() anywhere in the program except after the delay, so I have no idea what is causing it to play.
I explained my problem a little bit more in comments. Sorry if I didn't explain my code very well. If you could just tell my what else could be causing my player to start immediately, that would probably be enough.
'snd_btn_go is the button that is supposed to start it.
'This sub doesn't matter as much for the problem, it will just go to SndCueGO() if both numbers are in the valid range.
Private Sub snd_btn_go_Click(sender As Object, e As EventArgs) Handles snd_btn_go.Click
Dim cue1 As Integer
Dim cue2 As Integer
cue1 = If(Integer.TryParse(snd_txt_cue_1.Text, cue1), Int(snd_txt_cue_1.Text), snd_num1)
If snd_txt_cue_2.Text <> "" Then
cue2 = If(Integer.TryParse(snd_txt_cue_2.Text, cue2), Int(snd_txt_cue_2.Text), snd_num2)
Else
cue2 = -1
End If
If (cue1 <= dgSound.Rows.Count - 1 And cue1 > 0) Then
SndCueGO(cue1, cue2)
End If
End Sub
'This sub pulls all the info from the correct row in the DataGrid and assigns it to a list. It'll check if the start volume and end volume are the same and if they're not, it'll fade to the end volume.
Private Sub SndCueGO(cue1, cue2)
Dim cues() = {cue1, cue2}
snd_num1 = cue1
Dim cuedata1 = snd_ds.Tables(0).Rows(cue1 - 1)
Dim cuedata2 = snd_ds.Tables(0).Rows(cue1 - 1)
If cue2 <> -1 Then
snd_num2 = cue2
cuedata2 = snd_ds.Tables(0).Rows(cue2 - 1)
End If
Dim data() = {cuedata1, cuedata2}
For i = 0 To 1
If cues(i) <> -1 Then
snd_delay(i) = data(i).Item("Delay")
snd_startvol(i) = safeNum(data(i).Item("Start_Vol."))
snd_file(i) = data(i).Item("File")
snd_in(i) = data(i).Item("Fade_In")
snd_out(i) = data(i).Item("Fade_Out")
snd_vol(i) = safeNum(data(i).Item("Vol."))
snd_hold(i) = data(i).Item("Hold")
snd_af(i) = If(data(i).Item("AF") = "", False, True)
player_list(i).URL = snd_file(i)
snd_current(i) = snd_startvol(i)
If snd_startvol(i) <> snd_vol(i) Then 'snd_startvol(i) and snd_vol(i) were the same in all my tests, so this should not run.
snd_next(i) = snd_vol(i)
Dim num_steps_up = snd_in(i) * snd_speed
Dim num_steps_down = snd_out(i) * snd_speed
Dim diff = snd_vol(i) - snd_startvol(i)
Dim small_step As Single
If diff > 0 Then
small_step = diff / num_steps_up
ElseIf diff < 0 Then
small_step = diff / num_steps_down
End If
snd_steps(i) = small_step
timer_snd_fade.Tag = 0
timer_snd_fade.Enabled = True
End If
timer_snd_master.Tag = 0 'resets the tag to 0
timer_snd_master.Enabled = True 'Starts timer
End If
Next
End Sub
Private Sub timer_snd_master_Tick(sender As Object, e As EventArgs) Handles timer_snd_master.Tick
If sender.Tag = snd_delay(0) Then
Player1.Ctlcontrols.play() 'This is the only play command in the program
Debug.Print("tag " & sender.Tag) 'These print after the delay
Debug.Print("delay " & snd_delay(0))
End If
sender.Tag += 1
End Sub
Inspect the:
AxWindowsMediaPlayer player1 = ...; // get the player from UI
IWMPSettings sett = player.settings;
sett.autoStart == ??
see the docs.
Probably it is set to true, as it's default value. Simply set it to false it the player will not play until Ctlcontrols.play() is invoked.