VBA - How to declare "Cell" variable - vba

Apologies for the potentially very easy to answer question. I was trawling through some code on the site regarding how you search for a row and paste it in another worksheet, the code being the one below:
Sub Test()
For Each Cell In Sheets(1).Range("J:J")
If Cell.Value = "131125" Then
matchRow = Cell.Row
Rows(matchRow & ":" & matchRow).Select
Selection.Copy
Sheets("Sheet2").Select
ActiveSheet.Rows(matchRow).Select
ActiveSheet.Paste
Sheets("Sheet1").Select
End If
Next
End Sub
I was wondering what the "Cell" should be declared as, as in:
Dim Cell As ...
I'm aware that without "Option Explicit", this is irrelevant, but I'm curious nonetheless, so please do help and explain if you can.
Thank you for your help in advance :)

In your case, cell is a range, so
dim cell as range
And: Always use Option Explicit

Walking over a Range yields a Range so Dim Cell As Range
If in doubt ask VBA: msgbox TypeName(Cell)

You can use Range. They are somewhat interchangeable.

Sorry but that is horrible code and it offends the eyes. Find would be better, but just in the interest of better understanding
Sub Test()
Dim Cell as Range
For Each Cell In Sheets(1).Range("J:J")
If Cell.Value = "131125" Then
Cell.EntireRow.copy Destination:=Sheets("Sheet2").range("a" & cell.row)
'You might want to exit here if there's only one value to find with
'Exit For
End If
Next
End Sub

Related

Autofill to and Adjacent Cell

I'm very new to VBA and I can't quite find the answer im looking for. The rest of my code is working, but when it comes to autofilling, I can't seem to get it. I have a cell, and I want to autofill just to the cell below. I know its a very basic question, but any help is appriciated! Here's my code:
Selection.AutoFill Destination:= Range(Cells.ActiveCell.Offset(1,0), Type:= _
xlFillDefault
You could use Resize
Option Explicit
Sub Test()
Selection.AutoFill Destination:=ActiveCell.Resize(2, 1), Type:=xlFillDefault
End Sub
Try out these tests. The code for column A answers your original question.
Option Explicit
Sub AutofillTest()
Dim ws As Worksheet
Set ws = Worksheets("Sheet1")
Dim aRng1 As Range, aRng2 As Range
'Autofill beginnining with only one cell as a "seed"
ws.Range("a:d").Clear
Set aRng1 = ws.Range("a1:a1")
aRng1 = 1 'The "seed" cell
Set aRng2 = aRng1.Offset(1, 0)
aRng1.AutoFill Destination:=Range(aRng1, aRng2), Type:=xlFillSeries
'More fun tests
ws.Range("b1:b1") = 1
ws.Range("c1:c1") = 1
ws.Range("d1:d1") = CDate("5/1/2018")
ws.Range("b1:b1").AutoFill Destination:=Range("b1:b5"), Type:=xlFillSeries 'List of numbers
ws.Range("c1:c1").AutoFill Destination:=Range("c1:c5"), Type:=xlFillDefault 'Copy of one number
ws.Range("d1:d1").AutoFill Destination:=Range("d1:d5"), Type:=xlFillDefault 'List of dates
End Sub
.AutoFill is overrated, Both .FillDown/.FillRight and .DataSeries are usually better methods and filling everything at once with relative content is always an option for formulas or constants.
Selection.filldown 'ctrl+D is faster
'or,
Selection.cells(1).resize(2, 1).filldown
...
Selection.cells(1).resize(2, 1) = Selection.cells(1).formula
...
Selection.cells(1).resize(2, 1).DataSeries Rowcol:=xlColumns, Type:=xlLinear, Step:=1
...
'only if you're feeling lucky
selection.flashfill
You haven't provided anywhere near enough information to offer a definitive answer but all of the above are viable alternatives to the guessing game called .AutoFill with a Type:=xlFillDefault argument.

Add Comments to Specific cells in Range. Excel VBA

I am trying to add comments to specific cells in a range if they meet criteria. So I have a list in Sheet1 where the information is housed. I also have the cell value on sheet16 where I want the comment in column U, so it will say F6 in row U. I keep getting
Application-Defined or object-defined error
Any thoughts?
Thanks in Advance.
Sub Comments()
Dim rcell As Range
Sheet16.Range("C6:AR17").ClearComments
For Each rcell In Sheet1.Range("A2:A" & Sheet1.Range("A" & Sheet1.Rows.CountLarge).End(xlUp).Row)
If rcell.Offset(0, 1).Value(10) = Sheet7.Range("G1").Value(10) Then
commentvalue = rcell.Offset(0, 4).Value
Sheet16.Range("U" & rcell.Row).AddComment (commentvalue)
End If
Next rcell
End Sub
The AddComment method fails if there's already a comment on a cell. Do it like this:
Sub Comments()
Dim rcell As Range
Dim commentvalue As String
Sheet16.Range("C6:AR17").ClearComments
For Each rcell In Sheet1.Range("A2:A" & Sheet1.Range("A" & Sheet1.Rows.CountLarge).End(xlUp).row)
If rcell.Offset(0, 1).Value = Sheet7.Range("G1").Value Then
commentvalue = CStr(rcell.Offset(0, 4).Value)
With Sheet16.Range("U" & rcell.row)
.ClearComments '<=== :-)
.AddComment commentvalue
End With
End If
Next rcell
End Sub
Edit
As per #Jeeped's comment, you could want to "cumulate" comments. My assumption was that you ran the code once, then ran it again and hit the error because the first run had created the comments. Depending on what you try to achieve, you may want to systematically clear the comments in column U from rows 2 to your last row, outside of the loop, and remove the .ClearComments in the loop, in order to start clean each time. That's the simplest case. I'll let you work out the details if it's anything more complicated.

Setting variables VBA

complete novice here
I started some VBA a few days ago, I have simple question but cant seem to find what I am doing wrong.
I am trying to make a button which will take the coordinates of the active cell and compare them to another worksheet to retrieve a specific value from another table.
I set variables to the active cell column and row, I want to do this so I can later compare these locations to another worksheet and get the value at a specified position on another worksheet.
So far I have written simply what I could find on the internet as I have no formal training.
The msgbox at the end is just to test whether or not it actually picks up the reference.
Sub CommandButton1_Click()
Dim Arow As Range
Dim Acol As Range
Set Arow = Worksheets("Sheet1").Range(ActiveCell.Row)
Set Acol = Worksheets("Sheet1").Range(ActiveCell.Column)
MsgBox (Arow)
End Sub
So far I have error run-time error '1004' Application defined or object defined error highlighting the 4th Row. If anyone could help me solve this or redirect me to some help it would be much appreciated.
I think this won't work, you should put there
Set arow = Worksheets("Sheet1").Range(ActiveCell.Row & ":" & ActiveCell.Row)
Putting there simply number won't work. For the column, you should put there somethong like C:C. For getting letter of column, see this qestion: Function to convert column number to letter?
For more information about Range property, please see official documentation https://msdn.microsoft.com/en-us/library/office/ff836512.aspx.
The thing is, that you have to supply either the address in so called A1 reference, which is "A1", or "$A$1" or name of cell, etc, or you have to supply two Range objects, such as two cells Worksheets("Sheet1").Range(Worksheets("Sheet1").Cells(1,1), Worksheets("Sheet1").Cells(2,2)), which defines area starting with upper-left corner in first parameter and lower right in second parameter.
ActiveCell.Row and ActiveCell.Column returns you some Integer value representing number of row and column, i.e. if you point cell B4, ActiveCell.Row would return 4, and ActiveCell.Column gonna return 2. An Range() property need as an argument whole adress for some range, i.e. Range("C6") or Range("G3:J8").
When you have your column as a number, you can use Cells() property for pointing first and last cell in your range, i.e. Range(Cells(2, 4), Cells(6, 8) would be the same range as Range("D2:H6").
Following this, one of the ways that you can do what you have described is:
Sub CommandButton1_Click()
Dim Rng As Range
Set Rng = Worksheets("Sheet1").Cells(ActiveCell.Row, ActiveCell.Column)
End Sub
Now you have under variable Rng an Range of the same coordinates as ActiveCell, but in Sheet1. You can pass some value into i.e Rng.Value = "Hello World", paste something with Rng.PasteSpecial xlPasteAll etc.
if you want the value from other sheet at the same location as activeCell, use this code,
Private Sub CommandButton1_Click()
valueFromOtherSheet = Sheets("Sheet2").Range(ActiveCell.Address)
MsgBox (valueFromOtherSheet)
End Sub
Like the others have said, it's just about knowing your variable types. This is another way you could achieve what you want
Sub CommandButton1_Click()
Dim Acell As Range
Set Acell = Worksheets("Sheet2").Range(ActiveCell.Address)
MsgBox "Value on ActiveSheet: " & ActiveCell.Value & vbNewLine & _
"Value on Sheet2: " & Acell.Value
End Sub
Thank you everyone for the help and clarification, In the end I was able to come up with some code that seems to do what I need it to.
Private Sub CommandButton1_Click()
Dim cabDate As Range
Dim searchCol As Integer
Dim newindex As Range
Set cabDate = WorksheetFunction.Index(Range("A1:O9999"), ActiveCell.Row, 2)
searchCol = ActiveCell.Column
Set newindex = WorksheetFunction.Index(Worksheets("Deadlines").Range("A1:O9999"), cabDate.Row, searchCol)
MsgBox (newindex)
End Sub
I wasn't aware about conflicting data types so thank you all for the assistance.

Excel userform deleting entire row not just intended selction

I have a userform that has a drop down box in which a person can select a record to have deleted off a list.
The code below is deleting the ENTIRE ROW. I do not want that. I just want the cells between A:E cleared on my spreadsheet.
I am not sure how else to describe this so I apologize in advance. Here is the code:
Private Sub CheckBox1_Click()
End Sub
Private Sub CommandButton1_Click()
Dim lRw As Long
ActiveWorkbook.Sheets("RAWDATA").Visible = xlSheetVisible
'get the row number. add 2 because ListIndex starts at one
lRw = Me.ComboBox1.ListIndex + 2
ActiveWorkbook.Sheets("RAWDATA").Select
Cells(lRw, 1).EntireRow.ClearContents
ActiveWorkbook.Sheets("RAWDATA").Visible = xlSheetHidden
End Sub
Private Sub CommandButton2_Click()
ComboBox1.Value = ""
ComboBox1.Clear
ComboBox1.Clear
Unload Me
End Sub
Private Sub UserForm_Initialize()
'assumes data starts in A1 and has a header row
Me.ComboBox1.List = ActiveWorkbook.Sheets("RAWDATA").Cells(1, 2).CurrentRegion.Offset(1, 2).Value
End Sub
side note: You don't need to select the cells to manipulate the contents in vba.
Check out this link to explain that concept in more detail:
how-to-avoid-using-select-in-excel-vba-macros
This is the problem code. You are clearing the entire row, using ".EntireRow.ClearContents"
ActiveWorkbook.Sheets("RAWDATA").Select
Cells(lRw, 1).EntireRow.ClearContents
ActiveWorkbook.Sheets("RAWDATA").Visible = xlSheetHidden
Here are three solutions. Both should give you some insight into how the .Cells(row,col) idea works while using a loop. You are using a variable to control the row number, and the same concept can be applied to the column. Even though it's just 5 columns. It might be 50 for another project. So you can loop through them using a "For Loop" This is my preferred method.
If you want to get loopy, try something like this. Use a Variable for the Column
For lCol = 1 To 5
Sheets("RAWDATA").Cells(lRw, lCol).ClearContents
Next lCol
You can do one cell at a time Directly coding the column number:
Sheets("RAWDATA").Cells(lRw, 1).ClearContents
Sheets("RAWDATA").Cells(lRw, 2).ClearContents
Sheets("RAWDATA").Cells(lRw, 3).ClearContents
Sheets("RAWDATA").Cells(lRw, 4).ClearContents
Sheets("RAWDATA").Cells(lRw, 5).ClearContents
You can do one cell at a time Directly coding the column LETTER:
Sheets("RAWDATA").Cells(lRw, "A").ClearContents
Sheets("RAWDATA").Cells(lRw, "B").ClearContents
Sheets("RAWDATA").Cells(lRw, "C").ClearContents
Sheets("RAWDATA").Cells(lRw, "D").ClearContents
Sheets("RAWDATA").Cells(lRw, "E").ClearContents
edit: added some explanation and link
The cells(lRw, 1).EntireRow.ClearContents is your issue. The EntireRow function selects the row which is pointed to by cells(lRw, 1). The .ClearContents function clears what's selected. You should replace it with something like:
Range("A" & <the row number> & ":J" & <the row number>).clearcontents
Your variable lRw is supposed to hold the value of the row in which the selected project is located, correct? If so, then:
Range("A" & lRw & ":J" & lRw ).clearcontents
should work. You can change the column letters to whatever you'd like to clear.
I think PJ Rosenburg's solutions are bit impractical, but I agree with the fact that you should shy away from using the .select function. You can do everything you need to do without using it. You'll write much better code once you understand this concept. In fact, here's a rewrite of your commandButton1_click that should do the exact same thing, but with less code and is easier to read.
Private Sub CommandButton1_Click()
Dim lRw As Long
lRw = Me.ComboBox1.ListIndex + 2
with ActiveWorkbook.Sheets("RAWDATA")
.Visible = xlSheetVisible
.Range("A" & lRw & ":J" & lRw ).clearcontents
.Visible = xlSheetHidden
end with
end sub
Notice a couple of things:
No .select
Moving the assignment statement
The addition of the With/End With statements
Anyway, I hope this helps and better explains what I was trying to say earlier.

Autofill Application.Countifs.Formula VBA Excel

I think this might be a simple question but I can't seem to find a way to autofill an Application.WorksheetFunction.SumProduct(wsf.CountIf formula so that the row number would change as the formula goes down.
I want to autofill this formula for B2 till LastRow from Column A
Application.WorksheetFunction.SumProduct(wsf.CountIfs(Sheet2.Range(**B2 Here**), Doctors, Sheet2.Range(**B2 Here**), wsf.Transpose(Emergency)))
So lets assume that the last used row for column A is 6, so the formula should autofill from B2 until B6 such as:
B3 = Application.WorksheetFunction.SumProduct(wsf.CountIfs(Sheet2.Range(**B3 Here**)....
B4 = Application.WorksheetFunction.SumProduct(wsf.CountIfs(Sheet2.Range(**B4 Here**)....
B5 = Application.WorksheetFunction.SumProduct(wsf.CountIfs(Sheet2.Range(**B5 Here**)....
B6 = Application.WorksheetFunction.SumProduct(wsf.CountIfs(Sheet2.Range(**B6 Here**)....
I don't want to use .Formula "=SUMPRODUCT(COUNTIFS....." approach so that I can use arrays as the criteria vary according to the selected dropdown choices.
Any clues?
AutoFill can do this for you. Assuming your formula begins in B2 and the end row changes, the syntax would be:
LRow = Sheet1.Cells(Rows.Count,1).End(xlUp).Row
With Range("B2")
.Formula = 'Your formula here.
.AutoFill Destination:=Range("B2:B" & LRow)
End With
Another option would be using FillDown as AutoFill almost always have quirks. The syntax is pretty much the same:
LRow = Sheet1.Cells(Rows.Count,1).End(xlUp).Row
Sheet1.Range("B2").Formula = 'Your formula here.
Sheet1.Range("B2:B" & LRow).FillDown
Let us know if this helps.
UPDATE:
Much like Dave's answer, here's my take on your formula:
Sub Test()
Dim Sh As Worksheet
Set Sh = ThisWorkbook.Sheets("Sheet1") 'Modify as required.
With Sh
LRow = .Cells(Rows.Count, 1).End(xlUp.Row)
.Range("B2").Formula = "=SUMPRODUCT(COUNTIFS($C$2:$C$16, ""Doctors"", $I$2:$I$16, $B2))"
.Range("B2:B" & LRow).FillDown
End With
End Sub
HOWEVER, here's the clincher: If you are merely doing a COUNTIFS checking if Column C has Doctors as value and Column I has the value of B2, you should remove the SUMPRODUCT from your formula as it's not necessary. SUMPRODUCT was once the way to check multiple conditions, but in Excel 2007 and up, it's been completely replaced by COUNTIFS for simple multiple condition-based check-and-count. What I'm saying is, the proper code is pretty much the following:
Sub Test()
Dim Sh As Worksheet
Set Sh = ThisWorkbook.Sheets("Sheet1") 'Modify as required.
With Sh
LRow = .Cells(Rows.Count, 1).End(xlUp.Row)
.Range("B2").Formula = "=COUNTIFS($C$2:$C$16, ""Doctors"", $I$2:$I$16, $B2)"
.Range("B2:B" & LRow).FillDown
End With
End Sub
STILL, further formula forensics and evaluation reveal a trickier part: You are entering your formula in B2 and below, but your COUNTIFS is checking B2 and below as part of the condition as well. This is not only confusing but is also prone to error (if not already erroneous) as it will result into a circular reference.
At this point, my question now is, what exactly are you trying to check and/or count? This is more than just a VBA issue, in my opinion, as I believe that you are confused as to what and how you want to get your numbers. While our approach is sound and is basically perfect for your question, if the formula is incorrect, the above is useless. :)
Try this.
Here's how my data is laid out:
This code goes in regular module:
Sub Test(s As String) 'input frpm combo box
Dim Sh As Worksheet, LRow As Long
Set Sh = ThisWorkbook.Sheets("Sheet1") 'Modify as required.
If LCase(s) = "all" Then s = "*"
s = Chr(34) & s & Chr(34) 'bracket with quotes
With Sh
LRow = .Cells(Rows.Count, 1).End(xlUp).Row
.Range("B2").Formula = "=COUNTIFS($C$2:$C$16," & s & ", $I$2:$I$16, $A2)"
.Range("B2:B" & LRow).FillDown
End With
End Sub
This code goes in sheet module of combo box (Sheet1 in this instance).
Private Sub ComboBox1_Change()
Test Me.ComboBox1.Value
End Sub
I'm not sure of your formula results, but it is getting loaded correctly.