vba: variable not defined in activeCell - vba

I'm new to vba so am learning. I'm struggling to understand why this is failing in Excel 2016 and my research is drawing a blank. I have the following code
Option Explicit
Sub Range_End_Method()
Dim lRow As Long
Dim lCol As Long
Dim i As Integer
Dim rng As Range
Set rng = ActiveCell
lRow = Cells(Rows.Count, 1).End(xlUp).Row
lCol = Cells(1, Columns.Count).End(xlToLeft).Column
Do While rng.Value <> Empty
If InStr(rng.Value, "Petrol") = 0 Then
currentRow = ActiveCell.Row
Worksheets("MySheet").Cells(currentRow, 5) = "Shopping"
Set rng = rng.Offset(1)
rng.Select
Else
currentRow = ActiveCell.Row
Worksheets("MySheet").Cells(currentRow, 9) = "Not Found"
Set rng = rng.Offset(1)
rng.Select
End If
Loop
End Sub
If I open the vba editor and type this into a "Microsoft Excel Objects" sheet I don't get an error. But if I run as a "Modules" naming my module as "m_End" I get an error thrown up saying
Compile Error
Variable not defined
The variable it highlights in vba editor is "currentRow" from the line in the first "If condition":
currentRow = ActiveCell.Row
I don't understand what the difference is and how to fix the error.
Any help would be appreciated.

Since you posted the rest of your code, that error is clearly because you did not declare currentRow in your Dim statements. Possibly option Explicit was not in your sheet module, so no error.
In any event, go to Tools ► Options ► Editor ► Code Settings and Select Require Variable Declaration It will save you loads of debugging time in the future. Perhaps in your sheet module you did not have Option Explicit
I would declare it as a Long
Oh, and in VBA there is no advantage (and there are some disadvantages) to declaring a data type as Integer. They get converted to Longs internally anyway; and the values which can be assigned are limited. Check VBA specifications for data types for the various limits.

Related

"Object Required" when setting Active.Sheet to Range

I have tried about every solution that I could find.
What I am trying to do is run a Function for selected range (The ActiveSheet)
I can't even get to the looping part because it errors on line 5 (arc = ActiveSheet.Row.Count). The error it throws is "Object Required". I have tried several different solutions found online with no luck. I am a complete noob at excel vba (my background is vb.net and c#). I would greatly appreciate a nudge in the right direction on what going wrong. Thanks in advance :)
Sub TestV2()
Dim rng As Range
Dim selectedRange As Range
Dim arc As Range
Set arc = ActiveSheet.Rows.Count
Set selectedRange = ActiveSheet.Rows.Count
For Each rng In selectedRange.Cells
If Application.CalculationState = xlDone Then
FireValidate
End If
Next rng
End
End Sub
You're getting this error because you declared arc as Range but you are trying to assign a Long number to it.
The Set keyword is required in VBA, to assign object references.
Set arc = ActiveSheet.Rows.Count
Set selectedRange = ActiveSheet.Rows.Count
Both arc and selectedRange are declared As Range, which is an object type - so the Set keyword is correct.
The problem is with the expressions on the right-hand side of the assignment operator: ActiveSheet.Rows.Count evaluates to a Long integer, which is not an object type. ActiveSheet.Rows.Count gets you the number of rows on the ActiveSheet, ...which should be the same number regardless of what specific sheet is currently active (all sheets have the same number of rows).
Hence, object required: you can't legally assign a Range object reference to a Long integer value; you need the right-hand side expression to evaluate to an object reference.
Tim Williams' answer shows how you can correctly assign the selectedRange to the Application.Selection, assuming what's currently selected is a Range object (a type mismatch error will occur if that's not the case).
What I am trying to do is run a Function for selected range (The ActiveSheet)
ActiveSheet doesn't return the selected range - it gives you the sheet that's currently active.
I am a complete noob at excel vba (my background is vb.net and c#)
You can reference the Excel object model from VB.NET or C# as well, and automate Excel through Visual Studio Tools for Office (VSTO) if you're more comfortable with these more powerful .net languages - but the object model will behave identically.
If you just want the current selection then:
Set selectedRange = Selection
You could try to modify your code as follows:
Sub TestV2()
Dim rng As Range
For Each rng In Selection
If Application.CalculationState = xlDone Then
FireValidate
End If
Next rng
End Sub
Hopefully it helps you.
There are three errors in your code:
.1. The key error. Use ActiveSheet.Rows.Count directly may encounter "Object Required" exception, instead, you can use the following worked code:
Dim ws As Worksheet
Set ws = ActiveSheet
'MsgBox ws.Rows.Count
Set arc = ws.Rows.Count
As hod said(this is not the key issue, but need to fix),
You're getting this error because you declared arc as Range but you are trying to assign a Long number to it.
As William have pointed, you can use the Set selectedRange = Selection directly if you want to operate the selected range.
Sub TestV2()
Dim rng As Range
Dim selectedRange As Range
Set selectedRange = Selection
For Each rng In selectedRange.Cells
If Application.CalculationState = xlDone Then
'FireValidate
'MsgBox "OK"
End If
Next rng
End Sub
And I think most time we just need the UsedRange.Rows but not the Rows all.
ActiveSheet.UsedRange.Rows.Count for the current sheet.
Worksheets("Sheet name").UsedRange.Rows.Count for a specific sheet.

ThisWoorkbook runtime Error 438

I have a VBA to copy and paste unique values from Sheet1 onto Sheet3. However i get the runtime error 438 when i run the VBA.
My VBA looks like this:
Sub UniqueList()
Application.ScreenUpdating = False
Dim lastrow As Long
Dim i As Long
Dim dictionary As Object
Set dictionary = CreateObject("scripting.dictionary")
ThisWorkbook.Sheet1.Activate
lastrow = Sheet1.Cells(Rows.Count, "M").End(xlUp).Row
On Error Resume Next
For i = 1 To lastrow
If Len(Cells(i, "M")) <> 0 Then
dictionary.Add Cells(i, "M").Value, 1
End If
Next
Sheet3.Range("a2").Resize(dictionary.Count).Value = _
Application.Transpose(dictionary.keys)
Application.ScreenUpdating = True
MsgBox dictionary.Count & " unique cell(s) were found and copied."
End Sub
The line that gets the error is:
ThisWorkbook.Sheet1.Activate
I run the VBA using a button from Sheet3. But i also tried running it using AltF8 and AltF11 with sheet1 open, nothing works.
Im not really sure why i get that error so i hope that there is a person who can help with a solution
Sheet1 isn't a member of ThisWorkbook. ThisWorkbook is a Workbook instance, and Workbook objects don't expose "dynamic members" for every worksheet in their Worksheets collection. Hence error 438, Object does not support property or method.
Sheet1 is [I presume] the CodeName of a worksheet in ThisWorkbook: it's a global-scope Worksheet object VBA conveniently creates, named after the (Name) property of the document module.
That Sheet1 object has a Parent property; like every Worksheet object, it already knows what Workbook instance it belongs to:
Debug.Print Sheet1.Parent Is ThisWorkbook
IntelliSense has been trying to tell you that (by not listing a Sheet1 member) - listen to what it says!
That said, fixing the instruction like this:
Sheet1.Activate
...doesn't solve the other problem: you're using Activate only so that the unqualified Cells calls can refer to that specific worksheet:
For i = 1 To lastrow
If Len(Cells(i, "M")) <> 0 Then
dictionary.Add Cells(i, "M").Value, 1
End If
Next
Instead, qualify them:
For i = 1 To lastrow
If Len(Sheet1.Cells(i, "M")) <> 0 Then
dictionary.Add Sheet1.Cells(i, "M").Value, 1
End If
Next
And then the Activate call becomes completely useless.
These implicit ActiveSheet references can be easy to introduce, and hard to spot. Rubberduck (an open-source VBE add-in project I manage) can help you locate them (and other things):

Error 1004, Method 'Range' of object '_Worksheet' failed

I have lots of data (numbers) with heading in several worksheets that I am trying to zero. This is done on each column as follows: Taking the value of the first row in the column and subtracting this value from all rows in the column.
I have put together this code (may not be the best way, but Im new to VBA so :))
Dim ws As Worksheet
Dim Header As Range, Coldata As Range
Dim firstrow As Long
Dim cell As Range, cell2 As Range
Set ws = ActiveSheet
Set Header = ws.Range("B5:CJ5")
For Each cell In Header
If cell Is Nothing Then Exit For
firstrow = cell.Offset(2).Value
***Set Coldata = ws.Range(cell.offset(3),cell.Offset(3)).End(xlDown)***
cell.Value = 0
For Each cell2 In Coldata
cell2.Value = cell2.Value - firstrow
Next
Next
MsgBox "Done zeroing"
This sub is under the Module of the workbook I am working on. Whenever I run this sub from inside the VBA window it gives me the error I stated in the description on the Line of the code with **** around it.
When I try to run it from a workhsheet it says Cannot run the macro. The macro may not be avaiable in this worksheet or all macros may be disabled. The thing is I run another macro in the same module it works, so macros being disabled is out of the question.
What am I missing?
Thanks in advance!
Edit, I fixed it.. But running it takes SO much time? Excel freezes when I run it though?
You are over-specifying. Replace:
Set Coldata = ws.Range(cell.Offset(3)).End(xlDown)
with:
Set Coldata = cell.Offset(3).End(xlDown)
cell is fully qualified already.

Copying range of cells from one workbook to another yields 400 error

Okay, so I am relatively new to Excel VBA. I am trying to do something which seems quite simple to me and there are many, many examples of how to do it which I have read exhaustively but I cannot seem to get past this so...here goes.
I am trying to paste a range of cells from one worksheet to another in Excel Microsoft Office Professional Plus 2010. I think I have reduced the problem to the absolute simplest form possible to illustrate the problem. This is just a snippet. The VictimResults and TempWorksheet variables are set higher up. I didn't include the code because I thought it might confuse the articulation of the problem.
Dim SourceWorksheet As Worksheet
Dim TargetWorksheet As Worksheet
Dim SourceRange As Range
Dim TargetRange As Range
Set SourceWorksheet = VictimResults
Set TargetWorksheet = TempWorksheet
Set SourceRange = Cells(1, 1)
Set TargetRange = Cells(1, 1)
TargetWorksheet.Range(TargetRange) = SourceWorksheet.Range(SourceRange)
I have placed the variables SourceWorksheet, TargetWorksheet, SourceRange, and TargetRange in a watch and set a breakpoint at the last line and they are all valid objects (not null). When I step over the breakpoint I get a dialog box which simply says "400".
Any help is much appreciated.
---edit---
I have created this complete VBA file that replicates the problem. Thought that might help someone answer.
Option Explicit
Sub Main()
GetFirstWorksheetContainsName("Sheet1").Range(Cells(1, 1)).Value = GetFirstWorksheetContainsName("Sheet2").Range(Cells(1, 1)).Value
End Sub
Function GetFirstWorksheetContainsName(worksheetNameContains) As Worksheet
Dim m As Long
Dim result As Worksheet
m = 1
Do
If InStr(1, Sheets(m).Name, worksheetNameContains) Then
Set result = Sheets(m)
Exit Do
End If
m = m + 1
Loop Until m > ThisWorkbook.Worksheets.Count
Set GetFirstWorksheetContainsName = result
End Function
Here is something else I tried which yields something a little more verbose.
Option Explicit
Sub Main()
Sheets("Sheet1").Select
Range(Cells(1, 1)).Select
Selection.Copy
Sheets("Sheet2").Select
Range(Cells(1, 1)).Select
ActiveSheet.Paste
End Sub
It gives me a "Method 'Range' of object '_Global' failed" error when executing the first Range(Cells(1, 1)).Select line.
If you are trying to copy and paste why not use .copy and .pastespecial. They may slow down your code a little bit but as long as your aren't copying and pasting thousands of things it should be ok.
I'm not sure where the 400 is coming from, but the exception that is thrown is the same is in your verbose example (1004 - "Method 'Range' of object '_Worksheet' failed", and is thrown for the same reason.
The problem is how you're addressing the Range. Cells(1, 1) is implicitly set to the active worksheet, not whatever range you are passing it to as a parameter. Since you only need one cell, you can just use the .Cells property instead:
Sub Main()
GetFirstWorksheetContainsName("Sheet1").Cells(1, 1).Value = _
GetFirstWorksheetContainsName("Sheet2").Cells(1, 1).Value
End Sub
If you need to copy more than one cell, you'll have to either grab a reference to a worksheets instead of inlining the calls to GetFirstWorksheetContainsName if you use dynamic ranges:
Sub Main()
Dim source As Worksheet
Dim data As Range
Set source = GetFirstWorksheetContainsName("Sheet2")
Set data = source.Range("A1:B2")
GetFirstWorksheetContainsName("Sheet1").Range(data.Address).Value = data.Value
End Sub
Or hard code it:
Sub Main()
GetFirstWorksheetContainsName("Sheet1").Range("A1:B2").Value = _
GetFirstWorksheetContainsName("Sheet2").Range("A1:B2").Value
End Sub

VBA txt box pass thru to spreadsheet causing error 1004 - application or object defined error

I've been working with a similar For Each statement dozens of times and have never run into this before. This code is intended to return values from a txt box on a user form to the appropriate column in Sheet1 based on pmNum. I have other workbooks with this code and have never received this error.
My declaration of MyCell MyCell=nothing during debug for a Run-Time 1004 error, Application-defined or object-defined error.
Any help or pointers would be greatly appreciated.
Sub whatever ()
Dim myCell as range
Dim PmNum as string
Dim erow
erow = sheet1.cells(rows.count,2).end(xlup).offset(0,0).rows
pmNum = matupdate.txtPM.value
For each cell in worksheets("Sheet1").Range("B2:B" & erow)
If cell.value = pmNum Then
cell.offset(0,1).value = matupdate.txtdel.value
""
""
End if
Next
End sub
erow = sheet1.cells(rows.count,2).end(xlup).offset(0,0).rows
should be
erow = sheet1.cells(rows.count,2).end(xlup).offset(0,0).Row
Also worth adding Option Explicit to catch things like this, as well as declaring all your variables with the most appropriate type.