Keeping Dim value after if statement - vb.net

I've been programming for about two months now. I have a problem with keeping a dim value after an if statement. I have a loop that if doesn't add up to 100 (it is for a percentage) stops entering in a radgrid. My work around for this is to store the value in a textbox but this hardly seems efficient. So how do i store this value in memory as opposed to in a textbox. Here is the code.
Dim p As Integer = RadGridView1.CurrentRow.Index - 1
Try
For int1 = p To 0 Step -1
If RadGridView1.Rows(Row).Cells(1).IsCurrent AndAlso Me.RadGridView1.IsInEditMode AndAlso RadGridView1.ActiveEditor.Value <> 0 Then
If RadGridView1.Rows(int1).Cells(1).Value <> Nothing Then Exit For
Dim total As String = 0
total += RadGridView1.Rows(int1).Cells("PC").Value
Dim int2 As Integer
int2 += RadGridView1.Rows(int1 - 1).Cells("PC").Value
`this is my problem here i want this dim value after the if statement
Dim percenttotal = int2 + RadGridView1.Rows(Row - 1).Cells("PC").Value
'my workaround is to keep the value in a textbox
TextBox3.Text = int2 + RadGridView1.Rows(Row - 1).Cells("PC").Value
End If
Next
If RadGridView1.Rows(Row).Cells(1).IsCurrent AndAlso Me.RadGridView1.IsInEditMode AndAlso RadGridView1.ActiveEditor.Value <> 0 Then
' i want this code to be the above dim value not to come from a textbox
If TextBox3.Text <> 100 Then
MsgBox("Your % above does not equal 100", MsgBoxStyle.Critical, "Value Error")
e.Cancel = True
End If
End If

You are having a problem with Scope. I like to think of Scope as a set of boxes, like those nesting Russian dolls. You can keep smaller boxes inside other boxes. A new Scope gets created and placed INSIDE the previous scope every time code enters a Sub , function , loop , and a few other cases. When you declare a variable it is placed in the current scope. Your code will be able to access the variables from any scope that it is currently inside, but it can't see any variables that are declared inside the smaller scopes inside it. Your code "can see out, but not in".
The problem that you are having is that you are declaring your variable inside the "If" scope, and when it hits the "End If" that scope goes away, taking your variable with it. The solution is to declare your variable at a higher scope so that it sticks around for the entire time you need it. Try declaring your variable BEFORE the "If" and setting it's value inside.
BTW, this is also why the form controls work for storing your data. They exist at a very high scope, the lifetime of the form instance.
You can read more about how scope works in VB.NET here https://msdn.microsoft.com/en-us/library/1t0wsc67.aspx

You are likely running into variable scoping issues.
Consider the following code:
Public Class Form1
Dim counter As Integer
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim i As Integer
i += 1
counter += 1
MsgBox("i: was clicked " & i & " times!" & vbCrLf & "counter: was clicked " & counter & " times!")
End Sub
End Class
i is defined within the function, and therefore will have its value reset each time the function is called.
counter is defined as the class or module level, so it retains its value in between function calls and its value is persistent until the form closes.
See: https://msdn.microsoft.com/en-us/library/ms973875.aspx
Edit: The other folks are more correct in that a variable defined with a "block" like If, For, While, etc. will have the scope of that block.
See: https://msdn.microsoft.com/en-us/library/1t0wsc67.aspx

Related

VB: Check if Object has “Class” then Execute Code

I am looking to find something in Visual Basic that basically states that if something collides with something with a certain class, it executes code. I may not be using correct terms, so when I say object I mean like a label or picture box, and a class is... well like a class in HTML, I guess, like an object with a trait.
The pseudocode would look something like this:
If object.Bounds.IntersectsWith([object with certain class]) Then execute code
Otherwise, the game's 'if' statements will overwhelm... Also I am new to Visual Basic language, so please keep it as simple as possible.
Here is what I have already:
If carblue.Bounds.IntersectsWith(boundary1.Bounds) And directiona = 1 Then
directiona = 0
carblue.Top += 2
ElseIf carblue.Bounds.IntersectsWith(boundary1.Bounds) And directiona = 2 Then
directiona = 0
carblue.Left += 2
ElseIf carblue.Bounds.IntersectsWith(boundary1.Bounds) And directiona = 3 Then
directiona = 0
carblue.Top -= 2
ElseIf carblue.Bounds.IntersectsWith(boundary1.Bounds) And directiona = 4 Then
directiona = 0
carblue.Left -= 2
End If
Where carblue is the object being controlled, boundary1 is the obstacle that stops the car from moving (on collision) and directiona is the value of the direction the car is travelling (1 is up, 2 is left, etc).
(Moved from S.A. Programmers site)
Without actual sample code to work with, it's not easy to provide a specific solution. I don't know how many controls you have moving around, is it 2? 10? 10,000? Assuming you have 10+ controls moving around, this is how I would handle it.
I would use a datatable to keep a record of the Bounds for each Control that moves or is collidable. After a control moves, update that row in the datatable, look for collisions, then check the object types to determine what kind of class the collided object is, and then run the code as needed.
Public MovingControls As DataTable
Sub Main()
'Build the DataTable
MovingControls = New DataTable("ControlBounds")
MovingControls.Columns.Add("Name", GetType(String))
MovingControls.Columns.Add("x1", GetType(Integer))
MovingControls.Columns.Add("x2", GetType(Integer))
MovingControls.Columns.Add("y1", GetType(Integer))
MovingControls.Columns.Add("y2", GetType(Integer))
End Sub
'Call this only when a control/object is created
Sub MovingControlAdded(sender As Control)
Dim Row As DataRow = MovingControls.NewRow
Row("Name") = sender.Name
Dim BoundsRect As Drawing.Rectangle = sender.Bounds
Row("x1") = sender.Bounds.Left
Row("x2") = sender.Bounds.Right
Row("y1") = sender.Bounds.Bottom
Row("y2") = sender.Bounds.Top
MovingControls.Rows.Add(Row)
End Sub
'Call this only when a control/object has moved
Sub MovingControlMoved(sender As Control)
'Update the location of this Control
Dim Row() As DataRow = MovingControls.Select("Name = '" & sender.Name & "'")
'Select returns an array of Rows but there should only be 1 row for each Control
Row(0)("x1") = sender.Bounds.Left
Row(0)("x2") = sender.Bounds.Right
Row(0)("y1") = sender.Bounds.Bottom
Row(0)("y2") = sender.Bounds.Top
'Collision check
Dim CollidedRows() As DataRow = MovingControls.Select("(" & sender.Bounds.Right & " >= x1)" &
"AND (" & sender.Bounds.Left & " <= x2)" &
"AND (" & sender.Bounds.Bottom & " <= y2)" &
"AND (" & sender.Bounds.Top & " >= y1)" &
"AND (Name <> '" & sender.Name & "'")
'Determine the object type and execute necessary code
For Each CollidedRow As DataRow In CollidedRows
Dim CollidedControl As Control = Me.Controls.Item(CollidedRow("Name"))
If CollidedControl.GetType = GetType(Label) Then
'Do stuff for labels
ElseIf CollidedControl.GetType = GetType(Button) Then
'Do stuff for buttons
End If
Next
End Sub
Caveat: This assumes 1 control is moving at a time. If Control A moves into Control B but Control B moves away at the same time, this code will still call a collision even though the collision was avoided. If you have multiple controls moving, you may want to split the MovingControlMoved method into 2 methods, one for updating the table and one for collision checks. Handle all movement first, then handle all collisions.
Depending on the complexity, you may want to create custom classes for collidable controls that inherit an interface for collisions. You can use System.Reflection to call RunMeOnCollision. This would eliminate the list of If statements.
Interface iCollidableBase
Sub RunMeOnCollision()
End Interface
Public Class CollidableLabel
Inherits Label
Implements iCollidableBase
Public Sub RunMeOnCollision() Implements iCollidableBase.RunMeOnCollision
Me.Text = "I have been collided"
End Sub
End Class
Public Class CollidableButton
Inherits Button
Implements iCollidableBase
Public Sub RunMeOnCollision() Implements iCollidableBase.RunMeOnCollision
Me.Text = "Ouch, that collision hurt!"
End Sub
End Class
Again, not knowing the full context here, I can't test my solution against your code. If you can post some additional details, I might be able to help more.
-E
I found what I needed from my programming teacher, using arrays.
In the public sub:
Dim walls(17) As PictureBox
Where 17 is the number of (In this case) boundaries that your form has. Also change PictureBox to the object you are using (for example labels).
Then in your form load:
For i = 1 To 17
walls(i) = Me.Controls("boundary" & i)
Next
I'm honestly not 100% sure about this, but the "boundary" string is a section of the name of my PictureBoxes, that are acting as boundaries. There names are boundary1, boundary2, etc. So you might change "boundary" to what your object's names are.
Next, when you want to check for something using the boundaries, declare
For i = 1 To 17
Then when you want to close checking for it,
Next
For the checking of collisions, use this:
If object.Bounds.IntersectsWith(walls(i).Bounds) Then
So in this case, the If statement would go between the For and Next lines.

Check if a Range in Datagridview contains an "," if yes change it to ":"

My application contains a Datagridview, the user has the possibility to enter values like: Day, Time, how many hours did he work etc. The problem is that my second application calculates with this data. It has to be in a certain format.
Like time should be "09:15", but i noticed that some users are using "09,15" instead. Can you help me guys, I need a code that can check if a Range in Datagridview contains some " blacklisted char" and if yes, replaces it with the right one.
Thanks for all.
Do not save values as a string.
Validate input string straight in the needed type.
Then validated values pass to the second application.
In this case you don't need "blacklisted chars"
Private Sub DataGridView_CellValidating(sender As Object,
e As DataGridViewCellValidatingEventArgs)
If e.RowIndex < 0 Then Exit sub
Dim dgv As DataGridView = DirectCast(sender, DataGridView)
Dim columnIndexWithInteger As Integer = 2
Dim columnIndexWithDate As Integer = 3
Select Case e.ColumnIndex
Case columnIndexWithInteger
Dim temp As Integer
If Integer.TryParse(e.FormattedValue, temp) = False Then
e.Cancel = True
End If
Case columnIndexWithDate
Dim temp As Date
If Date.TryParse(e.FormattedValue, temp) = False Then
e.Cancel = True
End If
End Select
End Sub
In DataGridView, you have one handle that allows you to check the validity of an edited cell : CellValueValidating. It is called before the user change is taken into account (CellValueChanged event).
You can find example and explanation here :
- https://msdn.microsoft.com/en-us/library/ykdxa0bc(v=vs.110).aspx
- https://msdn.microsoft.com/en-us/library/7ehy30d4(v=vs.110).aspx
You can also have a look at CellValueChanged, CellValueValidated and CellEndEdit events.

For loop for bowling score array

I am trying to create a bowling program that will display the scores given in a multi-line text box. I've manage to get the program giving an output, but when it runs it skips asking for new inputs and just gives 5 0s on seperate lines and nothing else. I'm completely lost, any help is very much appreciated
EDIT: Sorry should have changed errors to reflect the programs changes, it looks like this now. It gives 0's instead of using the value I gave it, but it does ask for each input now.
For gameNumber As Integer = 1 To 5 Step 1
lblEnterScore.Text = "Enter Score for game #" & gameNumber
Dim Testint As Integer ' define an Integer for testing
Try
Testint = CInt(txtScoreInput.Text) ' try to convert whatever they entered to Int
Catch
MessageBox.Show("Entry is not an Integer") ' If you are here then the CInt failed for some reason, send a message
txtScoreInput.SelectAll()
txtScoreInput.Focus()
Exit Sub
End Try
If txtScoreInput.Text.Contains(".") Then
MsgBox("Bowling Score must be a whole number.")
txtScoreInput.SelectAll()
txtScoreInput.Focus()
Exit Sub
End If
If txtScoreInput.Text > MAXIMUM_SCORE Or txtScoreInput.Text < MINIMUM_SCORE Then
MsgBox("Bowling Score must be between 1 and 300.")
txtScoreInput.SelectAll()
txtScoreInput.Focus()
Exit Sub
End If
scoreInput(gameNumber) = CInt(txtScoreInput.Text)
' and store it in the array
' and increment the gamecounter for the next time through the loop
Next
'btnEnterScore.Enabled = False
' place the good score into the multi-line textbox
txtScoreOutputs.Text = gameScore & vbCrLf & txtScoreOutputs.Text
End Sub
If it was me, here's what I would do... Just a suggestion; I also cut out over half of your code and stopped it from throwing exceptions as well... You can put this in a click event or where ever you need it as well. You can modify this as well to take as many as you want from user input as well not just limit them from entering score's. Your user also has the option to get out of that loop when they choose to do so as well, not keeping them inside the loop...
Private ScoreLists As New List(Of Integer) 'Hold your inputted values
Private Const MAXIMUM_SCORE As Integer = 300 'Max score
Private Const MINIMUM_SCORE As Integer = 1 'Min score
Private blnStop As Boolean = False
Try
For gameNumber As Integer = 1 To 5
Dim intScore As Integer = 0
Do Until (intScore >= MINIMUM_SCORE And intScore <= MAXIMUM_SCORE) OrElse blnStop
If Not Integer.TryParse(InputBox("Please enter a score for game # " & gameNumber.ToString), intScore) Then
If MsgBox("Bowling Score must be a whole number. Stop getting scores?.", MsgBoxStyle.YesNo) = MsgBoxResult.Yes Then
blnStop = True
Exit For
End If
End If
Loop
ScoreLists.Add(intScore)
Next
'Display the results...
For i As Integer = 0 To ScoreLists.Count - 1
txtScoreOutputs.Text &= ScoreLists.Item(i.ToString)
Next
ScoreLists.Clear()
Catch ex As Exception
End Try
Construct your logic like this (pseudo):
Loop
{
AskUserForInput()
ProcessUserInput()
}
The loop part will control how many scores the user is prompted to enter. The AskUserForInput() function will prompt the user to type in a new score, and the ProcessUserInput() function will get the value and store it in an array or print it to the screen, etc.
Your current logic is not waiting for any new user input before trying to add to the scores. You are also getting zeros because you're setting the txtScoreOutputs with gameScore, which doesn't look like it's been set to the user's input.

Is possible to ignore the TextBox?

I'm creating a program to calculate the average. There are 12 TextBox and I want to create the possibility to leave some fields blank. Now there are only errors and the crash of the program. Is possible to create that?
This is part of code:
ItalianoScritto = (TextBox1.Text)
MatematicaScritto = (TextBox2.Text)
IngleseScritto = (TextBox3.Text)
InformaticaScritto = (TextBox4.Text)
ScienzeScritto = (TextBox5.Text)
FisicaScritto = (TextBox6.Text)
MediaScritto = (ItalianoScritto + MatematicaScritto + IngleseScritto + InformaticaScritto + ScienzeScritto + FisicaScritto) / 6
Label10.Text = Str(MediaScritto)
If i leave blank the textbox1 when I click on the button to calculate the average Vb says Cast not valid from the string "" to type 'Single' and the bar of te textbox1 become yellow
I would do the following:
Iterate over the textboxes and check if you can parse the value into an iteger. If yes, add it to a value list.
Then add all values from that list and divide it by the number of cases.
It is faster than big if-statements and resilient against error
dim TBList as new list(of Textbox)
'add your textboxes to the list here
TbList.add(Textbox1)
...
dim ValList as new List(Of Integer)
for each elem in Tblist
dim value as integer
If integer.tryparse(elem.text,value)=True
ValList.add(Value)
else
'report error or do nothing
end if
next
dim Result as Integer
Dim MaxVal as Integer =0
for each elem in ValList
Maxval +=elem
next
Result = MaxVal / ValList.count
If you need support for point values, just choose double or single instead of Integer.
Also: regardless what you do -CHECK if the values in the textboxes are numbers or not. If you omit the tryparse, somebody will enter "A" and your app will crash and burn
Also: You OPTION STRICT ON!
You just have to check if the TextBox is blank on each one before using the value:
If TextBox7.TextLength <> 0 Then
'Use the value inside
End If
The way to do it depends a lot of your code. You should consider editing your question giving more information (and code) in order to us to help you better.

WWBasic + SPSS, script to rename value labels

before I start I want to point out that I tagged this question as VBA because I can't actually make a new tag for Winwrap and I've been told that Winwrap is pretty much the same as VBA.
I'm working on SPSS V19.0 and I'm trying to make a code that will help me identify and assign value labels to all values that don't have a label in the specified variable (or all variables).
The pseudo code below is for the version where it's a single variable (perhaps inputted by a text box or maybe sent via a custom dialogue in the SPSS Stats program (call the .sbs file from the syntax giving it the variable name).
Here is the Pseudo Code:
Sub Main(variable As String)
On Error GoTo bye
'Variable Declaration:
Dim i As Integer, intCount As Integer
Dim strValName As String, strVar As String, strCom As String
Dim varLabels As Variant 'This should be an array of all the value labels in the selected record
Dim objSpssApp As 'No idea what to put here, but I want to select the spss main window.
'Original Idea was to use two loops
'The first loop would fill an array with the value lables and use the index as the value and
'The second loop would check to see which values already had labels and then
'Would ask the user for a value label to apply to each value that didn't.
'loop 1
'For i = 0 To -1
'current = GetObject(variable.valuelist(i)) 'would use this to get the value
'Set varLabels(i) = current
'Next
'Loop for each number in the Value list.
strValName = InputBox("Please specify the variable.")
'Loop for each number in the Value list.
For i = 0 To varLabels-1
If IsEmpty (varLabels(i)) Then
'Find value and ask for the current value label
strVar = InputBox("Please insert Label for value "; varLabels(i);" :","Insert Value Label")
'Apply the response to the required number
strCom = "ADD VALUE LABELS " & strVar & Chr$(39) & intCount & Chr$(39) & Chr$(39) & strValName & Chr$(39) &" ."
'Then the piece of code to execute the Syntax
objSpssApp.ExecuteCommands(strCom, False)
End If
'intCount = intCount + 1 'increase the count so that it shows the correct number
'it's out of the loop so that even filled value labels are counted
'Perhaps this method would be better?
Next
Bye:
End Sub
This is in no way functioning code, it's just basically pseudo code for the process that I want to achieve I'm just looking for some help on it, if you could that would be magic.
Many thanks in advance
Mav
Winwrap and VBA are almost identical with differences that you can find in this post:
http://www.winwrap.com/web/basic/reference/?p=doc_tn0143_technote.htm
I haven't used winwrap, but I'll try to answer with my knowledge from VBA.
Dim varLabels As Variant
You can make an array out of this by saying for example
dim varLabels() as variant 'Dynamically declared array
dim varLabels(10) as variant 'Statically declared array
dim varLabels(1 to 10) as variant 'Array starting from 1 - which I mostly use
dim varLabels(1 to 10, 1 to 3) 'Multidimensional array
Dim objSpssApp As ?
"In theory", you can leave this as a variant type or even do
Dim objSpssApp
Without further declaration, which is basically the same - and it will work because a variant can be anything and will not generate an error. It is good custom though to declare you objects according to an explicit datatype in because the variant type is expensive in terms of memory. You should actually find out about the objects class name, but I cannot give you this. I guess that you should do something like:
set objSpssApp = new <Spss Window>
set objSpssApp = nothing 'In the end to release the object
Code:
'loop 1
For i = 0 To -1
current = GetObject(variable.valuelist(i)) 'would use this to get the value
Set varLabels(i) = current
Next
I don't exactly know why you want to count from 0 to -1 but perhaps it is irrelevant.
To fill an array, you can just do: varLabels(i) = i
The SET statement is used to set objects and you don't need to create an object to create an array. Also note that you did not declare half of the variables used here.
Code:
strVar = InputBox("Please insert Label for value "; varLabels(i);" :","Insert Value Label")
Note that the concatenation operator syntax is &.
This appears to be the same in WinWrap:
http://www.winwrap.com/web/basic/language/?p=doc_operators_oper.htm
But you know this, since you use it in your code.
Code:
'intCount = intCount + 1 'increase the count so that it shows the correct number
'it's out of the loop so that even filled value labels are counted
'Perhaps this method would be better?
I'm not sure if I understand this question, but in theory all loops are valid in any situation, it depends on your preference. For ... Next, Do ... Loop, While ... Wend, in the end they all do basically the same thing. intCount = intCount + 1 seems valid when using it in a loop.
Using Next (for ... next)
When using a counter, always use Next iCounter because it increments the counter.
I hope this reply may be of some use to you!