Excel VBA Object Defined Error - excel

I am getting an object defined error with the below code. Any idea what could i be doing wrong? Thanks
Sub Loop_Test2()
Dim i As Integer
Dim j As Integer
Dim CountAll As Integer
Dim CountXL As Integer
ActiveSheet.Range("A1").Activate
CountAll = ActiveSheet.Range("A35")
MsgBox CountAll
For j = 1 To CountAll
i = 1
This is where the error occurs:
CountXL = Cells(i, j).Value
Continued:
MsgBox CountXL
For i = 1 To CountXL + 2
Cells(i + 2, j) = "Row " & i & " Col " & j
Next i
Next j
End Sub
I think it is an incorrect assignment. I'm not familiar with the correct syntax.
Error Details: "Run time error 1004. Application defined or object defined error

Before you edit your question, you was forget to initial your i .So just set the value for i.
In future, you may use Option Explicit at the top of Sub to make sure you declare the variable before using it.
So for your case, just need set i=1, and please declare all the variables as long instead of integer. You may refer here to find out the reason why use long instead of integer.

Related

Function changes value in sheet

I am creating a function which prototype is:
Function TableToText(ByVal Table As Range) As String
This function is supposed to give me a string and not modify the sheet at all. However the operations that I perform on Table (which is a Range) inside the function also modify my sheet.
I thought ByVal which is the default was supposed to prevent that?
I tried in my function to make another range but to make another Range you use Set so it wouldn't have solved the problem anyway...
Can someone point out what I am missing here? Thank you in advance! :)
The whole function is
Function TableToText(Table As Range) As String
Dim nbColumns As Integer, nbRows As Integer
Dim i As Integer, j As Integer, s As Integer
Dim max As Integer, difference As Integer
nbColumns = Table.Columns.Count
nbRows = Table.Rows.Count
With Table
'' adding the spaces
For j = 1 To nbColumns
max = 0
' Find the longest string in the column
For i = 1 To nbRows
If Len(.Cells(i, j).Value) > max Then
max = Len(.Cells(i, j).Value)
End If
Next i
' Adding the spaces and the |
For i = 1 To nbRows
If Len(.Cells(i, j).Value) < max Then
difference = max - Len(.Cells(i, j).Value)
For s = 1 To difference
.Cells(i, j) = CStr(.Cells(i, j).Value) + " "
Next s
End If
.Cells(i, j) = CStr(.Cells(i, j).Value) + "|"
Next i
Next j
'' Creating the plain text table string
For i = 1 To nbRows
For j = 1 To nbColumns
TableToText = TableToText + .Cells(i, j).Value
Next j
TableToText = TableToText & vbCrLf
Next i
End With
End Function
There's a lot of misleading information and confusion on this page.
I thought ByVal which is the default was supposed to prevent that?
The default is ByRef in VBA. This is unfortunate, because the vast majority of the time, what you mean to do is to pass things ByVal.
Objects are always passed by reference [...] ByVal is ignored.
No. Objects are never "passed", period. What's passed byref/byval is a reference to the object, i.e. a pointer. That does not mean object parameters are always passed ByRef at all.
Let's debunk this claim once and for all.
Public Sub DebunkObjectsAreAlwaysPassedByRefClaim()
Dim thing As Collection 'any object type will do
Set thing = New Collection
DoSomethingByVal thing 'we pass a COPY of the pointer
Debug.Print thing.Count 'no problems here
DoSomethingByRef thing 'we pass a reference to our local pointer; what could possibly go wrong?
Debug.Print thing.Count 'error 91! the object reference is gone!
End Sub
Private Sub DoSomethingByVal(ByVal o As Object)
Set o = Nothing 'affects the local copy only
End Sub
Private Sub DoSomethingByRef(ByRef o As Object)
Set o = Nothing 'affects the same object pointer the caller gave us. this is bad.
End Sub
ByRef vs ByVal makes a major difference: give a procedure your object pointer (ByRef), and they can do anything they like with it - including Set-assigning it to a completely different object reference, or making it Nothing. Give a procedure a copy of your object pointer (ByVal), and whatever they do with it (including Set-assigning it to a completely different object reference or making it Nothing) will only affect that copy.
In both cases, whether you've passed the pointer itself or a copy of it, either way you're giving the procedure access to the same object, so as GSerg explained, any instruction that affects a Range (which you can't create - all Range objects belong to Excel, all you ever get is a pointer to one), regardless of where the pointer comes from, will affect the Range instance state.
So if you don't want to affect any worksheet, don't affect any Range and work with arrays instead.
Objects are always passed by reference even if you specify the byval keyword.
You should use a temporary array to store your values.
For example, something like that :
Function TableToText(Table As Range) As String
Dim nbColumns As Integer, nbRows As Integer
Dim i As Integer, j As Integer, s As Integer
Dim max As Integer, difference As Integer
nbColumns = Table.Columns.Count
nbRows = Table.Rows.Count
Dim tmpValues(nbRows, nbColumns) As String
With Table
'' adding the spaces
For j = 1 To nbColumns
max = 0
' Find the longest string in the column
For i = 1 To nbRows
If Len(.Cells(i, j).Value) > max Then
max = Len(.Cells(i, j).Value)
End If
Next i
' Adding the spaces and the |
For i = 1 To nbRows
If Len(.Cells(i, j).Value) < max Then
difference = max - Len(.Cells(i, j).Value)
For s = 1 To difference
tmpValues(i, j) = CStr(.Cells(i, j).Value) + " "
Next s
End If
tempValues(i, j) = CStr(.Cells(i, j).Value) + "|"
Next i
Next j
'' Creating the plain text table string
For i = 1 To nbRows
For j = 1 To nbColumns
TableToText = TableToText + tmpValues(i, j)
Next j
TableToText = TableToText & vbCrLf
Next i
End With
End Function
Hope it helps.

Type mismatch when comparing two strings

I have the following code that is comparing a combobox on a userform(GUI) to a populated cell on sheet2 of my workbook and I am getting a "type mismatch" error. This was all working until another sub shifted some data into the cells being compared on sheet 2.
My issue lies with if Worksheets(sheet2).cells(1,i).value = LCase(GUI.superCB.Value) then
Worksheets(sheet2).cells(1,i).value Now shows up in the watch as a Variant/Integer which made me think that when the data was shifted it changed the "style" of that cell.
Private Sub NextButton_Click() ''' adds check boxes to frame
Dim i As Integer
'Dim superColm As Integer
For i = 5 To 12
If Worksheets(Sheet2).Cells(1, i).Value = LCase(GUI.superCB.Value) Then 'problem line is right here
superColm = i
Exit For
Else
End If
Next i
NextButton.Visible = False
superCB.Visible = False
Run.Visible = True
Frame1.Visible = True
Dim chk As Control
Dim idx As Integer
Dim lastrow As Integer
lastrow = Worksheets(Sheet2).Cells(Rows.Count, superColm).End(xlUp).Row
For idx = 1 To lastrow - 1
Set chk = GUI.Frame1.Controls.add("Forms.CheckBox.1", idx, True)
'set chk = gui.Frame1.Controls.Add(
chk.Visible = True
chk.Left = 5
chk.Top = (idx - 1) * (chk.Height + 2)
chk.Caption = Cells(idx + 1, superColm) & " " & idx
Next
With Me.Frame1
.ScrollBars = fmScrollBarsVertical
If lastrow <= 10 Then
.ScrollHeight = .InsideHeight * 1.5
ElseIf lastrow <= 15 Then
.ScrollHeight = .InsideHeight * 2.25
ElseIf lastrow <= 20 Then
.ScrollHeight = .InsideHeight * 3
ElseIf lastrow <= 25 Then
.ScrollHeight = .InsideHeight * 3.9
ElseIf lastrow <= 30 Then
.ScrollHeight = .InsideHeight * 4.75
ElseIf lastrow <= 35 Then
.ScrollHeight = .InsideHeight * 5.35
Else
.ScrollHeight = .InsideHeight * 6.25
End If
.ScrollWidth = .InsideWidth * 9
End With
End Sub
If I have sheet 2 as the active sheet Cells(1,i).value will work however, I need to have sheet 2 hidden from the user in the end. With this working it makes me think that the cell style is not the issue.
I have tried going to Excel.Workbooks("Shawn_sch_v1.2.xlsm").worksheets(sheet2).cells(1,i).value and everything down to the base cells() hoping it was missing a sheet reference but nothing has helped.
A String can safely be compared against any other data type in VBA... except Error.
Comparing a Variant/Error against anything will throw a type mismatch error.
This code is implicitly accessing whatever ActiveSheet is:
chk.Caption = Cells(idx + 1, superColm) & " " & idx
Cells should be qualified with the specific Worksheet object you mean to work with. If the active sheet contains a value that can't be coerced into a String (e.g. #VALUE! or #REF!), that will throw a type mismatch error.
Worksheets(Sheet2).Cells(1, i).Value = ...
Here Sheet2 is an identifier. The Worksheets indexer wants either an integer value, or a string. If Sheet2 is the code name of a worksheet in ThisWorkbook, you don't need to dereference it from Worksheets - just use it:
Sheet2.Cells(1, i).Value = ...
The Worksheet class doesn't have a default property, so Debug.Print Worksheets(Sheet2) throws error 438 object doesn't support this property or method - and a subsequent member call like .Cells(1, i), also throws a type mismatch error. If you don't have a Sheet2 string variable holding a worksheet name, I suspect that's the bug you're having right now... which means everything above is just what's waiting to bite you :)
If Sheet2 is a string variable that contains a valid sheet name, you can use the IsError function to verify whether a Variant is a Variant/Error:
If Not IsError(Sheet2.Cells(1, i).Value) Then
' value is safe to compare against a string
Else
' comparing the cell value to anything will throw error 13
End If
Lastly, I would advise against using Rows as a global variable, since it's already a global-scope identifier ([_Global].Rows, implicitly referring to ActiveSheet). Now, renaming that variable with Find/Replace is going to be pretty hard to do without breaking your code: Rubberduck's "rename" refactoring could probably help with doing that safely (disclaimer: I manage that OSS VBIDE add-in project).
This will be fixed with doing a check on the range object data type first.
Worksheets(Sheet2).Cells(1, i).Value is the range object. This can change data types every time the range is modified depending on how it is modified.
LCase(GUI.superCB.Value) This appears to be a form control. If the range is an integer, they cannot compare.
Try something like this:
Dim i As Integer
Dim iRange as String
'Dim superColm As Integer
`This is untested
For i = 5 To 12
iRange = Worksheets(sheet2).Cells(1, i).Text
If iRange = LCase(GUI.superCB.Value) Then 'problem line is right here
superColm = i
Exit For
Else
End If
Next i
The idea is to first be sure that the data types are the same.
You may need to use .Text or .Value2 instead of .Value for the range. If it is possible that the range object will be Empty or Nothing , then you also need to check for those too.
Edit: Changed .Value to .Text
Edit2: This answer is incorrect.

run-time error 13 - type mismatch in if function within for loop (trying to match error against string)

I am trying to locate the first cell (row) stating "#N/A" in specific columns. I cannot work around a type mismatch error I get. I have googled and read a lot of similar stackflow questions and answers but still could not solve it.
The main things I have tried so far (besides various little changes):
used the immediate window and debug print to check outputs (the GetDates sub is working correctly)
converting the collection to an array where I can define a data type
using a while function instead of for (in this case I get it to attempt the while function but on the last iteration I get a type mismatch again)
here is the full code:
Dim EndofWeekDates As New Collection
Dim EndofRange As New Collection
Dim lCol As Long
Dim lRow As Long
Dim i As Long
Dim j As Long
Dim v As Long
Dim x As Long
Sub GetDates()
Set EndofWeekDates = Nothing
i = 4
j = 1
lCol = Cells(1, Columns.Count).End(xlToLeft).Column
While j < lCol + 1
If Not IsEmpty(Cells(i, j).Value) And Not Cells(i, j).Value = "End" Then
EndofWeekDates.Add j
End If
j = j + 1
Wend
Call GetRange
End Sub
Sub GetRange()
Set EndofRange = Nothing
For x = EndofWeekDates.Count To 1 Step -1
lRow = Cells(Rows.Count, EndofWeekDates(x)).End(xlUp).Row
For v = 15 To lRow
If Cells(v, EndofWeekDates(x)).Value = "#N/A" Then
EndofRange.Add v
Exit For
End If
Next v
Next x
End Sub
I get the error in the following section on the IF line
For v = 15 To lRow
If Cells(v, EndofWeekDates(x)).Value = "#N/A" Then
EndofRange.Add v
Exit For
End If
Next v
The EndofWeekDates(x) should be constant during each 15 - lRow run while v changes. I have tried putting in the variable i (used earlier) instead of v and it works but only if i remains constant and is not changed in the for loop. As far as I can see the issue is with the v and not with EndofWeekDates(x). Furthermore, it seems that the issue only occurs when I do not use a constant but a changing number per for iteration. I tried to use the same while function as in GetDates but that did not solve it either.
Since v is declared as Long and I have also tried integer, I am stuck. Especially since the earlier used Cells.Value works with a Long which is increased in each iteration.
Your line
If Cells(v, EndofWeekDates(x)).Value = "#N/A" Then
is crashing because the cell does not contain the string "#N/A" but instead contains an error code, which Excel displays as #N/A.
A comparison of the error code to a string cannot be performed as there is no type conversion that allows the two sides of the comparison to be cast to a common data type - therefore it generates a "type mismatch" error.
The correct way to test for an #N/A error condition would be
If Application.IsNA(Cells(v, EndofWeekDates(x))) Then
This is a very peculiar error. I am not sure what is causing it but using Cells().Text instead of Cells().Value will work properly.
Try below
For v = 15 To lRow
If Cells(v, EndofWeekDates(x)).Text = "#N/A" Then
EndofRange.Add v
Exit For
End If
Next v
Alternatively,
For v = 15 To lRow
If Application.WorksheetFunction.IsNA(Cells(v, EndofWeekDates(x))) Then
EndofRange.Add v
Exit For
End If
Next v

Moving string's individual characters into array

There is a portion of my macro that tries to take a string and break down the characters into its own array value, as follows:
'matchName As String is called from the Sub parameter
Dim matchArray(1 To 30) As Characters
Dim i As Integer
i = 1
While Mid(matchName, i, 1) <> ""
matchArray(i) = Mid(matchName, i, 1)
i = i + 1
Wend
From what I know, this should run perfectly fine, but I'm running into:
runtime error '91': "Object variable or With block variable not set".
I honestly cannot figure out why this is the case and would love another pair of eyes (or more!) to see if I'm missing something.
Here is how to do it:
Dim matchArray
Dim i As Long
ReDim matchArray(1 To Len(matchName))
For i = 1 To Len(matchName)
matchArray(i) = Mid(matchName, i, 1)
Next
.
And while the above will work perfectly, this is more fun in one line and no loop:
myArray = Evaluate("transpose(mid(""" & matchName & """,row(1:" & Len(matchName) & "),1))")

How do I make an integer to null in Excel VBA?

I am trying to detect whether an integer was set, and if not, skip most of the code in the loop (using an if statement). Here is what I have so for.
Do While hws.Cells(r, 9).Value <> ""
On Error Resume Next
ar = Null
ar = aws.Range("A:A").Find(hws.Cells(r, 2).Value).Row
If Not IsNull(ar) Then
'work with ar'
End If
r = r + 1
Loop
However, when I run it, ar = Null has problems. It says "Invalid use of null".
Variables defined as Integer cannot be Null in VBA. You will have to find another way to do what you want. eg use a different data type or use a magic number to indicate null (eg -1).
In your example code, either ar will be assigned a Long value (Range.Row is a Long) or it will throw an error.
just use a variant and isempty:
Dim i
If IsEmpty(i) Then MsgBox "IsEmpty"
i = 10
If IsEmpty(i) Then
MsgBox "IsEmpty"
Else
MsgBox "not Empty"
End If
i = Empty
If IsEmpty(i) Then MsgBox "IsEmpty"
'a kind of Nullable behaviour you only can get with a variant
'do you have integer?
Dim j as Integer
j = 0
If j = 0 Then MsgBox "j is 0"
Find returns a range:
Dim rf As Range
With aws.Range("A:A")
Set rf = .Find(hws.Cells(r, 2).Value)
If Not rf Is Nothing Then
Debug.Print "Found : " & rf.Address
End If
End With
-- http://msdn.microsoft.com/en-us/library/aa195730(office.11).aspx

Resources