I've come across this behaivour in Excel. Given these cells:
A B C D
|---------|---------|---------|---------|
1 | merged cell text | foo | bar |
|---------|---------|---------|---------|
2 | | | | |
|---------|---------|---------|---------|
When Cell C1 is selected (foo), the following VBA statement returns an empty string:
Debug.Print Selection.Offset(0, -1).Range("A1").Value
This next VBA however returns the expected value (merged cell text):
Selection.Offset(0, -1).Select
Debug.Print Selection.Range("A1").Value
I can't for the life of my figure out why - surely as Offset returns a Range and Selection is also a Range, it's just breaking down the same behaivour over multiple lines, and getting different results. The behaivour does not occur when there are no merged cells.
Can anyone explain what's going on here?
This should be the reason:
Debug.Print Selection.Offset(0, -1).Range("A1").Value
Your current selection is C1, offset -1 column gives you B1. You are trying to print A1's value while selecting B1, thus gives nothing. Merged cell does not automatically cause both A1 and B1 being selected.
(you can test by printing B1's value instead). However:
Selection.Offset(0, -1).Select
Debug.Print Selection.Range("A1").Value
selects the range B1 first, which when merged, cause it to select both A1 and B1 on a application level, thus able to print A1's value
Hope that's clear to you
if you want to read the value in a1 from anywhere of the mergedcell,
Debug.Print Range("anyCellFormMergedRange").cells(1,1).Value 'wich gets the value from the first cell of a bigger range (here A1:B1)
or
Debug.Print Range("anyCellFormMergedRange").MergeArea(1, 1).value 'wich gets the value from the first cell of a MERGED range (here A1:B1)
'for a small mergedcell like yours, a simple .mergearea(1) works too
you can change the range to anything you need (selection, .offset(x,y), activecell ...) wich are also ranges.
if you want to use the whole mergedCells (A1:B1), without using .select :
(from C1)
Debug.Print selection.offset(0,-1).MergeArea.address
Also remember that comment, validation data, are also contained in the first cell of the range (A1 here).
Related
I am a newbie. I want to sum the squares of the numbers in the active column. I am getting an error 'object doesn't support this method'. Here is my code
Sub sum_squares()
Dim total As Integer
Dim c As Range
Dim d As Range
'set d equal to column from active cell down to last non-empty'
d = Range(ActiveCell, ActiveCell.endxldown)
total = 0
For Each c In d
total = total + c.Value ^ 2
Next c
End Sub
Appreciate the help.
Thanks
As has been pointed out you've got the syntax of xlDown incorrect.
You should also start at the bottom and move up - xlDown may not find the last cell.
E.g.
With a value in cell A1:A3 and A1 as the ActiveCell it will correctly return A3.
Same scenario but with A4 left blank and a value in A5 still returns A3.
Same scenario with A1 left blank it returns A2.
This will return a reference from the ActiveCell to the last cell containing a value in that column.
Note that if the ActiveCell is lower down than the last cell containing data you'll get a reference reflecting that.
Set d = Range(ActiveCell, Cells(Rows.Count, ActiveCell.Column).End(xlUp))
A Range can be made up of one or more cell references:
Range("A1") and Range("A1,A3,C5") reference individual cells.
Range("A1:C5") and Range("A1", "C5") reference all cells between the first and last address.
A Cell is a single cell reference that uses row and columns identifiers.
Cells("A1") will return an error as it's a full address.
Cells(1,"A") will return A1 (row 1, column A)
Cells(1,1) will also return A1 (row 1, column 1)
The code above is using two cell addresses to reference all cells between the two.
Range(ActiveCell,....) is the reference to the first cell.
Cells(Rows.Count, ActiveCell.Column) is the reference to the second cell using row numbers and column numbers.
If the ActiveCell is in column B then this is the same as writing Cells(1048573,2).
The End(xlUp) then goes from that cell back up to the first one containing data.
There is a syntax error in your code - .endxldown and add Set before assigning range.
Correct it to -
Set d = Range(ActiveCell, ActiveCell.End(xlDown)
I want to tranform the values.
Suppose in A1:A20 there are 20 values and in B1:B20 also 20 values.
I want to copy values of column B in such manner that outcome should be:
Cell A1 value is A1, cell A2 value is B1, cell A3 value is A2, cell A4 value is B1.
Likewise in cell A40 value is B20.
(for more clarity i have attached image)
So here first step is inserting blanck cells alternatively in column A
and than copy value of column B in that blank cells.
For more clarity Please find the image
.
Always post what you have tried first !
Sub test()
Application.ScreenUpdating = False
Dim i As Long
For i = 2 To 20 Step 2
Sheets("Sheet1").Range("A" & i).EntireRow.Insert
Next i
Sheets("Sheet1").Range("B1:B40").copy
Sheets("Sheet1").Range("A2").PasteSpecial Paste:=xlPasteAll, SkipBlanks:=True
Application.ScreenUpdating = True
End Sub
Maybe this is not exactly what you are looking for but an alternative solution is to use a regular formula like below.
=IFERROR(INDEX($A$2:$B$9,ROUNDDOWN(ROW()/2,0),ISODD(ROW())+1),"")
But this won't give the color you are looking for. Just throw out an alternative method for your reference.
I found a code online which works but I am failing to change it for my purpose. Each entry in my spreadsheet contains different formulas as well as an Iferror function with the aim of making cells with error messages appear as blank. For example lets say a cell E3 is dependent on cell F3 with a certain formula (for clarification lets say F3/2.5). It is obvious if there is no entry in cell F3 then an error message would display in cell E3. For this reason, I use the IFERROR function to display the cell as blank. The difficulty arises when I want to delete blank rows after a click on the macro button. However, since that cell does have an entry (a formula which in turn returns an error message), that cell does not delete. Also I need to run this code over 3 different selection ranges. Please can someone help! The code I found was from a different thread on this forum and is:
`sub foo()
dim r As Range, rows As Long, i As Long
Set r = ActiveSheet.Range("A1:Z50")
rows = r.rows.Count
For i = rows To 1 Step (-1)
If WorksheetFunction.CountA(r.rows(i)) = 0 Then r.rows(i).Delete
Next
End Sub`
Thanks Alot!
EDIT: If statement added to the autofilter as it was deleting a row when there were no blanks
You will want to set up a column in the spreadsheet with the following sumproduct:
=SUMPRODUCT((LEN(A1:F1)>0)*1)
This is calculating how many cells' values have a length more than 0 hence are not blank, you will need to adjust cell references accordingly as I tested on a small sample of fake data.
Following this you can just loop:
For i = rows To 1 Step (-1)
If Cells(i,"G") = 0 Then r.rows(i).Delete 'My formula is in column "G"
Next
Or set up an auto-filter and delete entire rows of the visible cells:
Dim lrow As Integer
If Not WorksheetFunction.CountIf(Range("G:G"), "0") = 0 Then
Range("A1:G1").AutoFilter
Range("A1:G1").AutoFilter Field:=7, Criteria1:="0"
lrow = Cells(rows.Count, 7).End(xlUp).Row + 1
Range("G2:G" & lrow).SpecialCells(xlCellTypeVisible).EntireRow.Delete
Range("A1:G1").AutoFilter
End If
The only problem with using a leading column to calculate for this is if you have a lot of data coming and going as you will need to replenish the formula, though you could use auto complete in the code i guess.
I have updated the document Google Drive
The problem, with a clearer explanation, is; On my C-D-E-F tab I have , in E12:E14, The VIP numbers. Next cell, F12:F14, labeled "Bulk" are empty. In these cells I want the value from the Data tab, cells T58 in F12, T61 in F13, and T64 in F14.
The bad news is this column will change every day with updated values, the good news is that the order will stay the same. So the lowest VIP tag 16001669, will be the first VIP total, middle is next, and last is last.
Then, I need the number of "Caged Tote's", under the number copied to the C-D-E-F tab, copied to the next cell.
Right now I have:
E11 F11 G11
VIP Bulk Totes
16001669
16001670
16001671
The output I am looking for is:
E11 F11 G11
VIP Bulk Totes
16001669 4 1
16001670 1 1
16001671 4 1
Can you not just use a VLookup formula?
=vlookup(value_looking for, range_table_to_look_in, column_to_return, false)
Failing that, if you're trying to achive in code (and can't just use application worksheetfunction vlookup() ) use the find method of range object.
Let rgSearch = the cell with the value you're looking for= 1234, 4567 etc, rgSearchList = the first column of that table you've listed, intCol = the column you want to return, i.e. three
Function GetThingy(rgSearch as range, rgSearchList as range, intCol as integer) as range
set rgMatch = rgSearchList.find(rgSearch.value, rgSearchList.cells(1,1), xlValues, xlWhole)
if not rgMatch is nothing then 'i.e. "if found"
GetThingy = rgMatch.offset(0, intCol - 1) ' have to remove one because this is an offset from rgMatch, not an absolute from left edge
else
GetThingy = nothing
end if
end function
I have a column whose header is a range of B1:C1. the data is more like
+----+----+
| Header |
+----+----+
| H2 | H3 |
+----+----+
| 1 | 2 |
| 3 | 4 |
+----+----+
I have a variable named rng such as
Set rng = Range("B1:C1")
now using rng variable, I want to select value "H3" or "2", or "4". I used the following syntax
rng.Offset(1,1).value
and isntead of giving me "H3" it gave me value from next colum i.e d2.
There is not a straight forward way to fix this unexpected behaviour. My understanding is that, regarding merged cells, the reference for the offset is based on the whole of the cell and that the merged cells are treated as one cell instead of many cells.
In your instance, if Range("B1:C1") is merged then the next column (i.e Offset(0,1)) is column D. Excel views the merged range as single cell and so from a visual standpoint the next column along is column D and not column C. This can be confusing in my view.
The best way to work around this is to avoid using merged cells as headers but instead use Centre Across Selection formatting:
1) De-merge Range("B1:C1")
2) Select Range("B1:C1") > Format > Cells
3) In Horizontal dialog box select 'Center Across Selection'
If you do that then the following code will work:
Sub GetOffsets()
Dim rng As Range
Set rng = Range("B1")
Debug.Print rng.Offset(1, 0) // H2
Debug.Print rng.Offset(2, 0) // 1
Debug.Print rng.Offset(3, 0) // 3
Debug.Print rng.Offset(1, 1) // H3
Debug.Print rng.Offset(2, 1) // 2
Debug.Print rng.Offset(3, 1) // 4
End Sub
If you really need to use merged cells, Excel has this "issue" when it comes to offsets from merged cells. In your case above, it does make sense that cell D2 becomes offset(1,1) from B1.
One solution is to use nested offsets:
You have your variable:
Set rng = Range("B1:C1")
Then use the following adjustment to your code:
rng.Offset(1,0).offset(0,1).value
This way, you first offset by row, to move down to B2, then offset by column to get to C2.