What method would make this code more efficient or proper? - vb.net

I have a program that collects information based on the radio buttons that are checked, as well as a checkbox.
Private Sub calculateBtn_Click(sender As Object, e As EventArgs) Handles calculateBtn.Click
Dim TypeCost As Integer
Dim ColorCost As Integer
Dim Foldable As Integer
If standardRbtn.Checked() Then
TypeCost = 99
End If
If deluxRbtn.Checked() Then
TypeCost = 129
End If
If premiumRbtn.Checked() Then
TypeCost = 179
End If
If blueRbtn.Checked() Then
ColorCost = 0
End If
If redRbtn.Checked() Then
ColorCost = 10
End If
If pinkRbtn.Checked() Then
ColorCost = 15
End If
If foldableCheckBox.Checked() Then
Foldable = 25
Else
Foldable = 0
End If
Dim Price As String = TypeCost + ColorCost + Foldable
priceTextBox.Text() = "$" & Price
End Sub
I have a strong feeling that this code can be simplified, but I just can't seem to think of what it is. My friend suggested Enumerations and Arrays, but I don't think those would work. Would they?
I have been searching around for a question similar to this for a while now.
I would also like to point out that the type radio buttons and the color radio buttons are in separate group boxes, so they function separately. Making it impossible for more than one type or color to be selected at the same time.
I have uptade the code to:
If standardRbtn.Checked() Then
TypeCost = 99
ElseIf deluxRbtn.Checked() Then
TypeCost = 129
ElseIf premiumRbtn.Checked() Then
TypeCost = 179
End If
If blueRbtn.Checked() Then
ColorCost = 0
ElseIf redRbtn.Checked() Then
ColorCost = 10
ElseIf pinkRbtn.Checked() Then
ColorCost = 15
End If
If foldableCheckBox.Checked() Then
Foldable = 25
Else
Foldable = 0
End If
I knew there was something extremely simply I would be able to do to sort of get rid of some of the repetitiveness. Thank you, phatfingers.
If there's any other ideas anyone would like to throw out, I would love to hear them. But this solution is good enough for me.

I simply went from using a bunch of if statements to "ElseIf". The updated code is in the original thread. :) - Thank you to phatfingers for the idea.

You could use a dropdown, which would probably be the lowest effort solution and allow you to dynamically add new options without rewriting anything.
You can then just fetch the value of the selected item.
https://forums.asp.net/t/988528.aspx?Dynamically+adding+items+in+DropDownList
So something like:
Private Sub OnFormLoad() //I forgot the exact name of the load event of the form and what it looks like
typeDropDown.Items.Add(New ListItem("Standard", "99"))
typeDropDown.Items.Add(New ListItem("Premium", "129"))
typeDropDown.Items.Add(New ListItem("Deluxe", "179"))
colorDropDown.Items.Add(New ListItem("Blue", "0"))
colorDropDown.Items.Add(New ListItem("Red", "10"))
colorDropDown.Items.Add(New ListItem("Pink", "15"))
End Sub
Private Sub calculateBtn_Click(sender As Object, e As EventArgs) Handles calculateBtn.Click
Dim Price as String = typeDropDown.SelectedValue + _
colorDropDown.SelectedValue + _
iif(foldableCheckBox.Checked(), 25, 0)
priceTextBox.Text() = "$" & Price
End Sub

Related

VB.net | Finding duplicates in a multidimensional array

I have two forms: Act9.vb and List.vb. The code in both forms is below. I'm using vb.net "4.7.2" in visual studio.
I have been very frustrated with this program for a while now. For some reason the program only checks new clients against the first and second clients already in the list. For example, if the following entries are in the list:
╔═════════╦═════════════╗
║ ClientA ║ 32423223343 ║
╠═════════╬═════════════╣
║ ClientB ║ 23422322343 ║
╠═════════╬═════════════╣
║ ClientC ║ 23423423423 ║
╠═════════╬═════════════╣
║ ClientD ║ 43533453333 ║
╠═════════╩═════════════╣
║ etc... ║
╚═══════════════════════╝
Then if I try to modify ClientA or ClientB (pressing btnModify and then typing "ClientA"/"ClientB" in the inputbox), then it works, but if I try the same with ClientC, D, E, etc. it doesn't. I get this message: "This client doesn't exist. Please try again."
Same thing with adding new clients: it won't let me add ClientA or B twice, but if I try to add Client C more then once it doesn't realize that it's already in the multidimensional array and let's me add it a second time.
If someone knows anything that can help, please share.
Thanks in advance!
Public Class Act9
Public Clients(1, 1) As String
Public size As Integer = 0
Sub Add()
Dim tempClient As String
Dim tempTel As String
tempClient = InputBox("Please enter the clients name :", "Name")
If Duplicate(tempClient) Then
MsgBox("This client already exists")
Else
tempTel = InputBox("Please enter the client's phone number:", "Phone number")
Clients(0, size) = tempClient
Clients(1, size) = tempTel
size += 1
ReDim Preserve Clients(1, size)
End If
End Sub
Function Duplicate(ByVal tempClient As String) As Boolean
Dim output As Boolean = False
For i As Integer = LBound(Clients) To UBound(Clients)
If Clients(0, i) = tempClient Then
output = True
End If
Next
Return output
End Function
Private Sub BtnAdd_Click(sender As Object, e As EventArgs) Handles btnAdd.Click
Add()
End Sub
Private Sub btnShow_Click(sender As Object, e As EventArgs) Handles btnShow.Click
List.ShowDialog()
End Sub
Private Sub btnErase_Click(sender As Object, e As EventArgs) Handles btnErase.Click
ReDim Clients(1, size)
List.lstClients.Items.Clear()
size = 0
End Sub
Private Sub btnModify_Click(sender As Object, e As EventArgs) Handles btnModify.Click
modify()
End Sub
Sub modify(Optional who As String = Nothing)
Dim change As Boolean = False
If who = Nothing Then who = InputBox("Please enter the name of the client you wish to modify:", "Modify")
For i As Integer = LBound(Clients) To UBound(Clients)
If Clients(0, i) = who Then
Clients(0, i) = InputBox("Please enter the new name for the client:", "Name")
Clients(1, i) = InputBox("Please enter the new phone number for the client", "Phone number")
change = True
Exit For
End If
Next
If change = False Then MsgBox("This client doesn't exist. Please try again.")
End Sub
End Class
Public Class List
Private Sub List_Load(sender As Object, e As EventArgs) Handles Me.Load
lstClients.Items.Clear()
For i As Integer = 0 To Act9.size - 1
lstClients.Items.Add(Act9.Clients(0, i) & vbTab & Act9.Clients(1, i))
Next
End Sub
End Class
#Craig Told me to use breakpoints which are the perfect tools for this. I'm very grateful for the advice.
Here is how I ended up getting it to work properly:
I replaced LBound and Ubound with my variable "size" (which was already taking care of counting the size of my multidimensional array).
The For loop in "Duplicate" becomes:
For i As Integer = 0 To size
If Clients(0, i) = tempClient Then
output = True
End If
Next
The one in "Modify becomes:
For i As Integer = 0 To size
If Clients(0, i) = who Then
Clients(0, i) = InputBox("Please enter the new name for the client:", "Name")
Clients(1, i) = InputBox("Please enter the new phone number for the client", "Phone number")
change = True
Exit For
End If
Next
The reason why your original code didn't work out is because you LBound/UBound on the first dimension but your array extends on the second dimension. The first dimension is only ever 0 to 1 so you only ever checked the second dimension indexes 0 and 1 (the first two items) for the name:
For i As Integer = LBound(Clients) To UBound(Clients)
If you use
LBound(Clients, 2) to UBound(Clients, 2)
It will get the upper limit of the second dimension rather than the first. UBound uses 1-based indexing whereas VB uses 0 based. If you want the same thing in 0 based you can use
Array.GetUpperBound(Clients, 1)
to find the limit of the second dimension
Other tips:
your modify method makes the same bounding mistake
if this were programming 201 you'd probably be using a List(Of Client), Client being a class having a pair of string properties for name and tel, and an overridden equals method that compares the name of an incoming Client, so that list.Contains can be used to prevent duplicates. Eventually you'd probably override GetHashCode too and use a HashSet(Of Client). And this whole thing would actually be a lot easier. Multidimensional arrays are usually a poor storage solution for.. well.. everything
your size variable is public; it should have a capital s
your modify method is a method; it should have a capital M. All methods in .net have capital initial letters
maybe btnErase should set the size before it redims
your duplicate method checks every item in the array. It carries on checking even if it already found a duplicate item. You can skip the part where you create a Boolean and just straight Return True inside the If; your keys are always in the last place you look because you stop looking when you find them :)
perhaps if you implement a FindIndex method that takes a name and returns the index of where that person is, or -1 if it didn't find them then you can use it for both IsDuplicate (call findindex and return true if the result is greater than -1) and for Modify (find the index of the person and change them or put a message Not Found if -1 comes bac). This means you can have just one method that searches the array and you use it twice. It means you Don't Repeat Yourself - a software engineering principle we try to stick to. At the moment your duplicate and modify methods both have the same loop (with the same bug)

If statements and picture box values issue

i'm trying to create a snap game but when it comes to checking if the picture box contains the correct image, it simply just does not work, i've done a bit of research regarding this and implemented the ideas. it does not throw up any sort of error but i just do not receive a increased value when i should. Please have a look at this code and tell me if you know where i'm going wrong.
Attempt 1:
Dim BirdPics() As Image = {My.Resources.Image_1}
If tbxAnimal_Group.Text = "Birds" And BirdPics.Contains(pbxPicture.Image) Then
CurrentPoints += 1
lblScore.Text = "Score:" & CurrentPoints
End If
Attempt 2
Dim BirdPics() As Image = {My.Resources.Image_1}
If tbxAnimal_Group.Text = "Birds" And pbxPicture Is BirdPics Then
CurrentPoints += 1
lblScore.Text = "Score:" & CurrentPoints
End If
Dont use "BirdPics.Contains"; it does not work like that.
Simple comparisons cannot be made on images.
IF ThisImage = ThatImage THEN ' doesn't necessarily work even though it will compile.
Create a structure or class and store them in a list.
Structure gameObjects
BirdPic as Image
BirdPicName as string
Position as Point
End Structure
DIM GamePictures(0) AS gameObjects
SUB Main()
' Create a new object
DIM newObj as New gameObjects
With newObj
.BirdPic = Image.FromFile("pics/bluejay.jpg")
.BirdPicName = "BlueJay"
.Position = new point(10, 20)
End With
AddObject(newObj)
for index = 0 to gamepictures.count - 1
If tbxAnimal_Group.Text = "Birds" AND GamePictures(index).BirdPicName = "BlueJay" THEN
' Do Something
End If
next
END SUB
Public Sub AddObject(obj as GameObjects)
DIM thisObjIndex as integer = GamePictures.Count
ReDim preserve GamePictures(thisObjIndex + 1)
GamePictures(thisObjIndex) = obj
End Sub

What is wrong with my subroutines?

So I've been working on this project for a couple of weeks, as I self teach. I've hit a wall, and the community here has been so helpful I come again with a problem.
Basically, I have an input box where a user inputs a name. The name is then displayed in a listbox. The name is also put into an XML table if it is not there already.
There is a button near the list box that allows the user to remove names from the list box. This amends the XML, not removing the name from the table, but adding an end time to that name's child EndTime.
If the user then adds the same name to the input box, the XML gets appended to add another StartTime rather than create a new element.
All of this functions well enough (My code is probably clunky, but it's been working so far.) The problem comes when I try to validate the text box before passing everything through to XML. What I am trying to accomplish is that if the name exists in the listbox on the form (i.e hasn't been deleted by the user) then nothing happens to the XML, the input box is cleared. This is to prevent false timestamps due to a user accidentally typing the same name twice.
Anyhow, I hope that makes sense, I'm tired as hell. The code I've got is as follows:
Private Sub Button1_Click_2(sender As System.Object, e As System.EventArgs) Handles addPlayerButton.Click
playerTypeCheck()
addPlayerXML()
clearAddBox()
End Sub
Private Sub playerTypeCheck()
If playerTypeCBox.SelectedIndex = 0 Then
addMiner()
ElseIf playerTypeCBox.SelectedIndex = 1 Then
addHauler()
ElseIf playerTypeCBox.SelectedIndex = 2 Then
addForeman()
End If
End Sub
Private Sub addMiner()
If minerAddBox.Text = String.Empty Then
Return
End If
If minerListBox.Items.Contains(UCase(minerAddBox.Text)) = True Then
Return
Else : minerListBox.Items.Add(UCase(minerAddBox.Text))
End If
If ComboBox1.Items.Contains(UCase(minerAddBox.Text)) = True Then
Return
Else : ComboBox1.Items.Add(UCase(minerAddBox.Text))
End If
End Sub
Private Sub addPlayerXML()
If System.IO.File.Exists("Miners.xml") Then
Dim xmlSearch As New XmlDocument()
xmlSearch.Load("Miners.xml")
Dim nod As XmlNode = xmlSearch.DocumentElement()
If minerAddBox.Text = "" Then
Return
Else
If playerTypeCBox.SelectedIndex = 0 Then
nod = xmlSearch.SelectSingleNode("/Mining_Op/Miners/Miner[#Name='" + UCase(minerAddBox.Text) + "']")
ElseIf playerTypeCBox.SelectedIndex = 1 Then
nod = xmlSearch.SelectSingleNode("/Mining_Op/Haulers/Hauler[#Name='" + UCase(minerAddBox.Text) + "']")
ElseIf playerTypeCBox.SelectedIndex = 2 Then
nod = xmlSearch.SelectSingleNode("/Mining_Op/Foremen/Foreman[#Name='" + UCase(minerAddBox.Text) + "']")
End If
If nod IsNot Nothing Then
nodeValidatedXML()
Else
Dim docFrag As XmlDocumentFragment = xmlSearch.CreateDocumentFragment()
Dim cr As String = Environment.NewLine
Dim newPlayer As String = ""
Dim nod2 As XmlNode = xmlSearch.SelectSingleNode("/Mining_Op/Miners")
If playerTypeCBox.SelectedIndex = 0 Then
newMinerXML()
ElseIf playerTypeCBox.SelectedIndex = 1 Then
newHaulerXML()
ElseIf playerTypeCBox.SelectedIndex = 2 Then
newForemanXML()
End If
End If
End If
Else
newXML()
End If
End Sub
Private Sub nodeValidatedXML()
If playerTypeCBox.SelectedIndex = 0 Then
minerValidatedXML()
ElseIf playerTypeCBox.SelectedIndex = 1 Then
haulerValidatedXML()
ElseIf playerTypeCBox.SelectedIndex = 2 Then
foremanValidatedXML()
End If
End Sub
Private Sub minerValidatedXML()
If minerListBox.Items.Contains(UCase(minerAddBox.Text)) = False Then
appendMinerTimeXML()
End If
End Sub
Private Sub appendMinerTimeXML()
Dim xmlSearch As New XmlDocument()
xmlSearch.Load("Miners.xml")
Dim docFrag As XmlDocumentFragment = xmlSearch.CreateDocumentFragment()
Dim cr As String = Environment.NewLine
Dim newStartTime As String = Now & ", "
Dim nod2 As XmlNode = xmlSearch.SelectSingleNode("/Mining_Op/Miners/Miner[#Name='" & UCase(minerAddBox.Text) & "']/StartTime")
docFrag.InnerXml = newStartTime
nod2.AppendChild(docFrag)
xmlSearch.Save("Miners.xml")
End Sub
And lastly, the clearAddBox() subroutine
Private Sub clearAddBox()
minerAddBox.Text = ""
End Sub
So, I should point out, that if I rewrite the nodeValidated() Subroutine to something like:
Private Sub nodeValidatedXML()
If playerTypeCBox.SelectedIndex = 0 Then
appendMinerTimeXML()
ElseIf playerTypeCBox.SelectedIndex = 1 Then
appendHaulerTimeXML()
ElseIf playerTypeCBox.SelectedIndex = 2 Then
appendForemanTimeXML()
End If
End Sub
then all of the XML works, except it adds timestamps on names that already exist in the list, which is what i'm trying to avoid. So if I haven't completely pissed you off yet, what is it about the minerValidated() subroutine that is failing to call appendMinerTimeXML()? I feel the problem is either in the minerValidated() sub, or perhaps clearAddBox() is somehow firing and I'm missing it? Thanks for taking the time to slog through this.
Edit: Clarification. The code as I have it right now is failing to append the XML at all. Everything writes fine the first time, but when I remove a name from the list and then re-add, no timestamp is added to the XML.
You need to prevent the user accidentally typing the name twice.(Not sure if you mean adding it twice)
For this I believe you need to clear the minerAddBox.Text in your addminer() if this line is true.
minerListBox.Items.Contains(UCase(minerAddBox.Text)) = True
minerAddBox.Text = ""
Return
Now it will return back to your addplayerXML which will Return to your clearbox(), since you have this in your addplayerXML()
If minerAddBox.Text = "" Then
Return
Now you get to your clearbox() (Which is not really needed now since you cleared the minerAddBox.Text already)
when I remove a name from the list and then re-add, no timestamp is added to the XML.
your minerValidatedXML() is true, because you are not clearing the textbox when you re-add a name to the list box. Or you may need to remove the existing listbox item if it is the same as the textbox
If minerListBox.Items.Contains(UCase(minerAddBox.Text)) = True Then
minerListBox.Items.remove(UCase(minerAddBox.Text))

Debugging using a timer

I'm making a Console game where a moving character has to move left and right to intercept falling 'fruit'/ASCII characters, only I'm having trouble. I'm using a timer with a 1 second interval, and every time it elapses it's supposed to check a list of fruit that's already on the board and move each fruit down by one, and then it randomly inserts a new fruit onto the board. Fruits are all kept as objects in a class.
Here's the timer code:
Sub FruitTick() Handles FruitTimer.Elapsed
Dim RandomNumber As Integer
Dim Fruit As Fruit
For i = 0 To FruitList.Count - 1
If FruitList(i).Position.Y < FruitBoard.Height - 1 Then
FruitList(i).LowerFruitByOne()
End If
Next
PeriodUntilFruitAppears -= 1
If PeriodUntilFruitAppears <= 0 Then
PeriodUntilFruitAppears = FruitFrequency
RandomNumber = New Random().Next(1, 5)
If RandomNumber = 1 Then
Fruit = New Fruit()
Fruit.AddToList()
Fruit.PlaceOnBoard()
End If
End If
End Sub
And here's the class for Fruit:
Public Class Fruit
Private FruitIcons() As Char = {"#", "ð", "ó", "ç", "%", "$"}
Public Icon As Char
Public Position As Location
Public Colour As ConsoleColor
Sub New()
Me.Icon = FruitIcons(New Random().Next(FruitIcons.Length))
Me.Position = New Location(New Random().Next(FruitBoard.Width), 0)
Me.Colour = New Random().Next(1, 16)
End Sub
Sub New(_Icon As Char, _
_Position As Location, _
_Colour As ConsoleColor)
Me.Icon = _Icon
Me.Position = New Location(_Position.X, 0)
Me.Colour = _Colour
End Sub
Sub PlaceOnBoard()
Console.SetCursorPosition(FruitBoard.Position.X + Me.Position.X, FruitBoard.Position.Y + Me.Position.Y)
Console.ForegroundColor = Me.Colour
Console.BackgroundColor = FruitBoard.BackColour
Console.Write(Me.Icon)
End Sub
Sub AddToList()
FruitList.Add(Me)
End Sub
Sub LowerFruitByOne()
Dim DrawInstruction As Instruction
DrawInstruction = New Instruction(" ", _
New Location(FruitBoard.Position.X + Me.Position.X, _
FruitBoard.Position.Y + Me.Position.Y), _
FruitBoard.BackColour, _
FruitBoard.BackColour)
DrawInstruction.Execute()
Me.Position.Y += 1
DrawInstruction = New Instruction(Me.Icon, _
New Location(FruitBoard.Position.X + Me.Position.X, _
FruitBoard.Position.Y + Me.Position.Y), _
Me.Colour, _
FruitBoard.BackColour)
DrawInstruction.Execute()
End Sub
End Class
The Instruction class referred to is simply used to redraw characters in the Console.
I'm having weird problems, such as trailing characters where they should have been drawn over by a blank space, the fruit falling two characters instead of one, fruit spawning to the left of the previous fruit and then stopping, etc... but I'm especially having a problem debugging it. When I put a breakpoint in and step into the code, the debugger seems to go from place to place erratically, as if the timer's still running while it's paused and I'm too slow.
Is there any way to debug it properly, line-by-line, or am I going to have to make intelligent guesses about what's going on?
You should stop the timer while in the elapsed method. Try to stop the timer on the beggning and enabling it on the last line.
Sub FruitTick() Handles FruitTimer.Elapsed
FruitTimer.Enabled = False
' Your actual code
FruitTimer.Enabled = True
End Sub
Probably, your code last more than a second and the code starts again before the last execution is complete. Which is more evident when debugging. It will probably be generating all your problems and it will cause memory issues on the end.

Trouble with Timer_tick not stopping

I'm very new to programming and vb.net, trying to self teach more so as a hobby, as I have an idea for a program that I would find useful, but I am having trouble getting past this issue and I believe it is to do with the timer.
I have a form of size.(600,600) with one button of size.(450,150) that is set location(100,50) on the form. When clicked I want to move down it's own height, then add a new button in it's place. The code included below works as desired for the first two clicks, but on the third click the button keeps moving and the autoscroll bar extends. I initially thought it was the autoscroll function or the location property, but realised that as the button keeps moving, the timer hasn't stopped. I am aware that the code is probably very clunky in terms of achieving the outcome, and that there are a few lines/variables that are currently skipped over by the compiler (these are from older attempts to figure this out).
I have looked around and can't find the cause of my problem. Any help would be greatly appreciated. Apologies if the code block looks messy - first go.
Public Class frmOpenScreen
Dim intWButtons, intCreateButtonY, intCreateButtonX 'intTimerTick As Integer
Dim arrWNames() As String
Dim ctrlWButtons As Control
Dim blnAddingW As Boolean
Private Sub btnCreateW_Click(sender As System.Object, e As System.EventArgs) Handles btnCreateW.Click
'Creates new Button details including handler
Dim strWName, strWShort As String
Dim intCreateButtonY2 As Integer
Static intNumW As Integer
Dim B As New Button
strWName = InputBox("Please enter the name name of the button you are creating. Please ensure the spelling is correct.", "Create W")
If strWName = "" Then
MsgBox("Nothing Entered.")
Exit Sub
End If
strWShort = strWName.Replace(" ", "")
B.Text = strWName
B.Width = 400
B.Height = 150
B.Font = New System.Drawing.Font("Arial Narrow", 21.75)
B.AutoSizeMode = Windows.Forms.AutoSizeMode.GrowAndShrink
B.Anchor = AnchorStyles.Top
B.Margin = New Windows.Forms.Padding(0, 0, 0, 0)
'Updates Crucial Data (w name array, number of w buttons inc Create New)
If intNumW = 0 Then
ReDim arrWNames(0)
Else
intNumW = UBound(arrWNames) + 1
ReDim Preserve arrWNames(intNumW)
End If
arrWNames(intNumW) = strWShort
intNumW = intNumW + 1
intWButtons = WButtonCount(intWButtons) + 1
'updates form with new button and rearranges existing buttons
intCreateButtonY = btnCreateW.Location.Y
intCreateButtonX = btnCreateW.Location.X
‘intTimerTick = 0
tmrButtonMove.Enabled = True
‘Do While intTimerTick < 16
‘ 'blank to do nothing
‘Loop
'btnCreateW.Location = New Point(intCreateButtonX, intCreateButtonY + 150)
B.Location = New Point(intCreateButtonX, intCreateButtonY)
Me.Controls.Add(B)
B.Name = "btn" & strWShort
intCreateButtonY2 = btnCreateW.Location.Y
If intCreateButtonY2 > Me.Location.Y Then
Me.AutoScroll = False
Me.AutoScroll = True
Else
Me.AutoScroll = False
End If
'MsgBox(intCreateButtonY)
End Sub
Function WButtonCount(ByRef buttoncount As Integer) As Integer
buttoncount = intWButtons
If buttoncount = 0 Then
Return 1
End If
Return buttoncount
End Function
Public Sub tmrButtonMove_Tick(sender As System.Object, e As System.EventArgs) Handles tmrButtonMove.Tick
Dim intTimerTick As Integer
If intTimerTick > 14 Then
intTimerTick = 0
End If
If btnCreateW.Location.Y <= intCreateButtonY + 150 Then
btnCreateW.Top = btnCreateW.Top + 10
End If
intTimerTick += 1
If intTimerTick = 15 Then
tmrButtonMove.Enabled = False
End If
End Sub
End Class
So my current understanding is that the tick event handler should be increasing the timertick variable every time it fires, and that once it has hits 15 it should diable the timer and stop the button moving, but it is not doing so.
Thanks in advance.
IntTimerTick is initialized to 0 at the beginning of every Tick event. This won't happen if you declare it to be static:
Static Dim intTimerTick As Integer