VBA: Why can't I use "If x is null then...", but "dim q = isNull(x) / if q then..." works fine? - vba

I'm very new to VBA so forgive my structure if it's inefficient. I'm trying to differentiate between a new record being added to a table in Access versus a blank field of an existing record being updated. My code below works as I intend it to.
Private Sub x_BeforeUpdate(Cancel As Integer)
Dim Q, W As Boolean
Q = IsNull(x.OldValue)
W = IsNull(x)
If Me.NewRecord Then
...
Exit Sub
ElseIf Q And Not W Then
...
Exit Sub
ElseIf W And Not Q Then
...
Exit Sub
End If
...
End Sub
My question is mostly about the fact that when it looked like the next code block, I would always get an error on the first line for "x.OldValue is Null".
Private Sub x_BeforeUpdate(Cancel As Integer)
If Me.NewRecord Then
...
Exit Sub
ElseIf x.OldValue is Null And x is Not Null Then
...
Exit Sub
ElseIf x.OldValue is Not Null and x is Null Then
...
Exit Sub
End If
...
End Sub
What is the big difference between these two blocks of code? Why does declaring a variable work but using "x is Null" does not?

Related

If condition being ignored

I'm currently writing code for a game called Caladont.
The game is about first player saying the word and the next one has to say the word that starts with last two letters of previous word.
The problem comes when I want to check if word contains less than 3 letters or if it's empty.
In the first cycle when list for filling is still empty, everything is fine.
However, after I type for example 5 or more words and type a single letter or leave it empty, it prints two "You've lost!" messages, which means that code from if statement is being ignored since it changes bool variable to false and is supposed to exit the While loop.
I've tried replacing ok = false with Exit While in condition which checks if words contains less than 3 letters and it worked, but I want to understand what is the problem.
The code can also be found here [Caladont game
GitHub](https://github.com/whistleblower91/VB.net/blob/master/Caladont%20game):
Module Module1
Sub Main()
Kaladont()
End Sub
Sub Kaladont()
Const msg As String = "You've lost!"
Dim list As New List(Of String)
Dim word As String
Dim i As Integer
Dim ok As Boolean
ok = True
While ok
Console.Write("Insert word:")
word = Console.ReadLine()
list.Add(word)
If word.Length < 3 Or word = "" Then
Console.WriteLine(msg)
ok = False
End If
If list.Count > 1 Then 'Skip checking first word
For i = 0 To list.Count - 2
If word.ToLower = lista(i).ToLower Then
Console.WriteLine(msg)
ok = False
End If
Next
If LastTwo(word) = "ka" Or LastTwo(word)="nt" Then
Console.WriteLine("KALADONT! You won!")
ok = False
End If
If FirstTwo(list.Last) <> LastTwo(list(list.Count - 2)) Then
Console.WriteLine(msg)
ok = False
End If
End If
End While
Check()
End Sub
Function FirstTwo(ByVal s1 As String) As String
Return Left(s1.ToLower, 2)
End Function
Function LastTwo(ByVal s2 As String) As String
Return Right(s2.ToLower, 2)
End Function
Sub Check()
Dim sign As Char
Console.WriteLine("Do you want to start new game? y\n")
sign = Console.ReadLine()
If sign = CChar("y") Then
Console.Clear()
Kaladont()
ElseIf sign = CChar("n") Then
Exit Sub
End If
End Sub
End Module
Any solutions?
Even if you set ok to false, it will still go inside the other loop, you'll need to use Else
If word.Length < 3 Or word = "" Then
Console.WriteLine(msg)
ok = False
Else If list.Count > 1 Then 'Skip checking first word
An other way would be to exit the while with End while.
If word.Length < 3 Or word = "" Then
Console.WriteLine(msg)
ok = False
Exit While
End If

Do Until Loop checking for duplicates wont stop looping

I'm trying to do a Do Until Loop to check for duplicates in my combo box. It runs the loop but it never stops looping.
Dim i As Integer = 0
Dim flavors As Integer = flavorsComboBox.Items.Count
Do Until (i < flavors - 1)
If flavors = flavorsComboBox.Items.Count Then
MessageBox.Show("Flavor Already Exists!", "Error")
Else
flavorsComboBox.Items.Add(flavorsComboBox.Text)
End If
Loop
The condition of the loop looks at the i variable and the flavors variable:
Do Until (i < flavors - 1)
But those variables don't ever change at any point in the body of the loop:
If flavors = flavorsComboBox.Items.Count Then
MessageBox.Show("Flavor Already Exists!", "Error")
Else
flavorsComboBox.Items.Add(flavorsComboBox.Text)
End If
You need to add code to change one or both of those variables. But that's still the hard way to do this. Just use the Distinct() method:
Dim items = flavorsComboBox.Items.Distinct().ToArray()
flavorsComboBox.Items.Clear()
flavorsComboBox.Items.AddRange(items)
Here is a simple do until loop
Dim i as integer = 0
Dim flavors as Integer = 10
do until (i > flavors -1)
Console.WriteLine(i.ToString())
i = i +1
loop
Output
0
1
2
3
4
5
6
7
8
9
In your code:
do until (i < flavors - 1)
if i = 0 and flavors is the Count -1 when is 0 greater than count, to enter the condition of the loop.
The next omission is that you never change the value of condition variable of looping, to have an accurate evaluation of the condition to stop the loop.
Try this:
Option Strict On
Option Explicit On
Option Infer Off
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
If AddDistinct(flavorsComboBox, "test") Then
MsgBox("Item did not exist, so it was added.")
Else
MsgBox("Item already existed, so it was not added.")
End If
End Sub
Public Function AddDistinct(cboBox As ComboBox, value As Object) As Boolean
If cboBox.Items.IndexOf(value) = -1 Then cboBox.Items.Add(value) : Return True
Return False
End Function
End Class
You are not resetting the value of flavors
Try this:
Dim i As Integer = 0
Dim flavors As Integer = flavorsComboBox.Items.Count
Do Until (i < flavors - 1)
If flavors = flavorsComboBox.Items.Count Then
MessageBox.Show("Flavor Already Exists!", "Error")
Else
flavorsComboBox.Items.Add(flavorsComboBox.Text)
flavors = flavorsComboBox.Items.Count
End If
Loop

How to dynamically count UBound() values?

I got something like this:
For i = 1 to 4
cur_tab = "tab_event" & i
For e = 1 to Ubound(cur_tab)
' do something
Next
Next
I need to dynamically change the cur_tab , but it's not working due to Ubound(cur_tab) is returning a String(e.g.) *Ubound("tab_event1")*
*I've declared all vars and of course I have 'i' tables
"Subscript out of range"
Any ideas ?
What you are trying to achieve is called Variable Variables. It doesn't work like that in VBA. If you have a common procedure then use a separate procedure and use that again and again.
For example, your code can be written as
Sub Sample()
'
'~~> Rest Of Your Code
'
For e = 1 To UBound(tab_event1)
MySub
Next
For e = 1 To UBound(tab_event2)
MySub
Next
For e = 1 To UBound(tab_event3)
MySub
Next
For e = 1 To UBound(tab_event4)
MySub
Next
'
'~~> Rest Of Your Code
'
End Sub
Sub MySub()
MsgBox "Hello World!"
End Sub

Error ending For/Next loop through CheckBoxes

I have UserForm4 which contains CheckBox1...19 and also OptionButton1...3, along with TextBox1, CommandButton1, 2.
When OptionButton 1 = True I want to loop through all CheckBoxes and set each to True.
The error I get states "Cannot find object" and i = 21, n = 23. How are they getting that high, when I only have 19 CheckBoxes?
Thanks!
Private Sub OptionButton1_Click()
Dim ctrl As Control
Dim i As Integer
Dim n As Integer
n = 0
For Each ctrl In UserForm4.Controls
If TypeOf ctrl Is MSForms.CheckBox Then
n = n + 1
End If
Next ctrl
For i = 1 To n
If UserForm4.Controls("CheckBox" & i) = False Then
UserForm4.Controls("CheckBox" & i) = True
End If
Next i
End Sub
Did you create more than 19 initially and delete some? Each VBA object has a unique name. Doing this the way you are doing it is likely to cause all sorts of problems.
For example, if you create 10 CheckBoxes and delete 8 of them, the remaining two might be named Checkbox8 and Checkbox9. So your loop will not hit them at all.
Also, why not do something like the following:
Private Sub OptionButton1_Click()
Dim ctrl As Control
Dim i As Integer
Dim n As Integer
n = 0
For Each ctrl In UserForm4.Controls
'this will make your problem really obvious
debug.print ctrl.name
If TypeOf ctrl Is MSForms.CheckBox Then
ctrl.value = True
End If
Next ctrl
End Sub

Visual Basic If Not Issue

I am doing my homework for my visual basic class. I have most of the code written and everything seems to be working well except for my If Not statement that catches the exception when the loop does not find what it is looking for. Anyone see a problem with the way the code looks. The file is loaded in using the browse button already and it works find when I enter information that the loop can find.
Private Sub btnSearch_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs)
Handles btnSearch.Click
'event level variables
Dim Found As Boolean
Dim Counter As Integer
'looks for entry match
If rdoAbbrev.Checked = True Then
Do Until Found Or Counter > 257
If Country(Counter).Abbreviation.ToUpper = txtAbbrev.Text.ToUpper Then
Found = True
txtCountry.Text = Country(Counter).Names
Else
Counter += 1
End If
Loop
Else
Do Until Found Or Counter > 257
If Country(Counter).Names.ToUpper = txtCountry.Text.ToUpper Then
Found = True
txtAbbrev.Text = Country(Counter).Abbreviation
Else
Counter += 1
End If
Loop
If Not Found Then
MessageBox.Show("This is not a valid entry.", "NO MATCH FOUND", MessageBoxButtons.OK)
If rdoAbbrev.Checked = True Then
txtAbbrev.Text = ""
txtAbbrev.Focus()
Else
txtCountry.Text = ""
txtCountry.Focus()
End If
End If
End If
'match not found response
'reset variables
Counter = 0
Found = False
End Sub
You If Not Found block only occurs if rdoAbbrev.Checked = True. Is that what you intended? If not, then that block of code should either be located outside of the first If block (below it) or you should have a second If block after the first While loop.
EDIT
It looks like Country is an array. You should probably use Counter >= Country.Length.
Arrays in VB.NET are 0-based. Meaning that the first item is located at Country(0), the second item is at Country(1), etc. If there are 100 elements in the array, then the last element is located at Country(99). Country(100) does not exist and will cause an Exception if you try to access it.
I'm not sure what the requirements of your homework are, but usually to iterate over the elements of a collection (array, list, etc), you would use a For loop. You can jettison from the loop early with the Exit command.
For Counter As Integer = 0 To Country.Length - 1
'...Country(Counter)
If Found Then Exit For
Next
Assuming you want the "Not Found" part to execute regardless of the rdoAbbrev.Checked property, it looks like a slight error in your logic (easily fixed).
Private Sub btnSearch_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSearch.Click
'event level variables
Dim Found As Boolean
Dim Counter As Integer
'looks for entry match
If rdoAbbrev.Checked = True Then
Do Until Found Or Counter > 257
If Country(Counter).Abbreviation.ToUpper = txtAbbrev.Text.ToUpper Then
Found = True
txtCountry.Text = Country(Counter).Names
Else
Counter += 1
End If
'You could also write this as:
'Found = Country(Counter).Abbreviation.ToUpper = txtAbbrev.Text.ToUpper
'If Found Then
' txtCountry.Text = Country(Counter).Names
'Else
' Counter += 1
'End If
Loop
Else
Do Until Found Or Counter > 257
If Country(Counter).Names.ToUpper = txtCountry.Text.ToUpper Then
Found = True
txtAbbrev.Text = Country(Counter).Abbreviation
Else
Counter += 1
End If
'You could also write this as:
'Found = Country(Counter).Names.ToUpper = txtCountry.Text.ToUpper
'If Found Then
' txtAbbrev.Text = Country(Counter).Abbreviation
'Else
' Counter += 1
'End If
Loop
End If
'match not found response
'Move your "Not Found" here so that the not found works regardless of the rdoAbbrev.Checked property.
If Not Found Then
MessageBox.Show("This is not a valid entry.", "NO MATCH FOUND", MessageBoxButtons.OK)
If rdoAbbrev.Checked = True Then
txtAbbrev.Text = ""
txtAbbrev.Focus()
Else
txtCountry.Text = ""
txtCountry.Focus()
End If
End If
'reset variables
Counter = 0
Found = False
End Sub
Probably you should End the If statements within their range in the code and avoid ending all your If statements at the end of the code lines. usually works for me in Basic. I think that Basic has a lot of advantages, but for me it still not a high level language that has some problems because it is so easy to work with.