VBA Code


Find the Last Populated Cell

ActiveSheet.UsedRange.Rows.Count 
ActiveSheet.UsedRange.Columns.Count
Range("A1048576").End(xlUp).Row

Another way is to use VBA to reset the CutCopyMode property. This doesn't work if macros are disabled.

Sub Workbook_SheetSelectionChange(ByVal sh As Object, _ 
                                  ByVal Target As Range)
   Application.CutCopyMode = False
End Sub

What is the difference between UsedRange and CurrentRegion

UsedRange - the cell range of all the used cells on the worksheet.
CurrentRegion - the cell range inside blank rows and columns.

ActiveSheet.UsedRange.Row 
ActiveSheet.ActiveCell.CurrentRegion.Select

What is the difference between Range.Value and Range.Value2

The Value2 Property does not recognise (and convert into) the VBA Currency data type or the VBA Date data type.
Range.Value - This returns the formatted value.
Range.Value2 - This returns the actual numerical value without formatting.


Empty Cells

The best way to test if a cell is empty is to use the IsEmpty() function.

If VBA.IsEmpty = False Then 

Testing for a zero-length string will be true when a formula returns a zero-length string

If rgeCell.Value <> "" Then 

No Cell Object

There is no Cell object nor is there a Cells collection.
Individual cells are treated as Range objects that refer to one cell.


Contents of a Cell

The easiest way to find what the contents of a cell are is to use the Visual Basic TypeName function

Range("A1").Value = 100 
Range("B1").Value = VBA.TypeName(Range("A1").Value) = "Double"

Range("A2").Value = #1/1/2006#
Range("B2").Value = VBA.TypeName(Range("A2").Value) = "Date"

Range("A3").Value = "some text"
Range("B3").Value = VBA.TypeName(Range("A3").Value) = "String"

Range("A4").Formula = "=A1"
Range("B4").Value = VBA.TypeName(Range("A4").Value) = "Double"

Text Property

You can assign a value to a cell using its Value property.
You can give a cell a number format by using its NumberFormat property.
The Text property of a cell returns the formatted appearance of the contents of a cell.

Range("A1").Text = "$12,345.00" 

Range Object

The Range object can consist of individual cells or groups of cells.
Even an entire row or column is considered to be a range.
Although Excel can work with three dimensional formulas the Range object in VBA is limited to a range of cells on a single worksheet.
It is possible to edit a range either using a Range object directly (e.g. Range("A1").BackColor ) or by using the ActiveCell or Selection methods (e.g. ActiveCell.BackColor )


Cells Property

Application.Cells 
ActiveSheet.Cells
ActiveCell
Cells

When the cells property is applied to a Range object the same object is returned.
It does have some uses though:
     ● Range.Cells.Count - The total number of cells in the range.
     ● Range.Cells(row, column) - To refer to a specific cell within a range.

ActiveSheet.Cells(2,2) = ActiveSheet.Range("B2") 
  • To loop through a range of cells

For irow = 1 to 4 
   For icolumn = 1 to 4
      ActiveSheet.Cells(irow,icolumn).Value = 10
   Next icolumn
Next irow

Dim objRange As Range 
Set objRange = ActiveSheet.Range(ActiveSheet.Cells(1,4), ActiveSheet.Cells(2,6))

Cells automatically refer to the active worksheet.
If you want to access cells on another worksheet then the correct code is:

Range( Worksheets(n).Cells(""), Worksheets(n).Cells("") ) 

Range Property

Application.Range 
ActiveSheet.Range
Range

When Range is not prefixed and used in a worksheet module, then it refers to that specific worksheet and not the active worksheet.


Selection Property

Selection will return a range of cells
Be aware that the Selection will not refer to a Range object if another type of object, such as a chart or shape is currently selected.
Using the Selection object performs an operation on the currently selected cells.
If a range of cells has not been selected prior to this command, then the active cell is used.

Selection.Resize(4,4).Select 

It is always worth checking what is currently selected before using the Selection property.

If TypeName(Selection) = "Range" Then 
End If

Relative References

It is important to remember that when a Cells property or a Range property is applied to a Range object, all the references are relative to the upper-left corner of that range.

ActiveSheet.Range("B2:D4").Cells(2,2) = ActiveSheet.Range("C3") 
ActiveSheet.Range("B2:D4").Range("B2") = ActiveSheet.Range("C3")

ActiveCell returns a reference to the currently active cell
This will only ever return a single cell, even when a range of cells is selected.
The active cell will always be one of the corner cells of a range of cells. - will it what if you use the keyboard ??


Total number of populated cells

iTotal = Application.CountA(ActiveSheet.Cells) 

Window Object Only

This property applies only to a window object
This will enter the value 12 into the range that was selected before a non-range object was selected.

ActiveWindow.RangeSelection.Value = 12 

Window.RangeSelection property is read-only and returns a Range object that represents the selected cells on the worksheet in the active window.
If a graphic object is active or selected then this will returns the range of cells that was selected before the graphic object was selected.


Counting

Dim ltotal As Long 
ltotal = Cells.Count 'returns a long

Dim dbtotal As Double
dbtotal = Cells.CountLarge ' returns a double

Range of a Range

It is possible to treat a Range as if it was the top left cell in the worksheet.
This can be used to return a reference to the upper left cell of a Range object
The following line of code would select cell "C3".

Range("B2").Range("B2").Select 

Range("B2").Cells(2).Select 

Remember that cells are numbered starting from A1 and continuing right to the end of the row before moving to the start of the next row.

Range("B2").Cells(2,2).Select 

An alternative to this is to use the Offset which is more intuitive.


Range.Address

The Address method returns the address of a range in the form of a string.

Range("A1:B3").Address = "$A$1:$B$3" 
Range("A1:B3").Address(False,False) = "A1:B3"

Using the parameters allows you to control the transformation into a string (absolute vs relative).

Range.Address([RowAbsolute], 
              [ColumnAbsolute],
              [ReferenceStyle],
              [External],
              [RelativeTo]) As String

RowAbsolute - True or False, default is True
ColumnAbsolute - True or False, default is True
ReferenceStyle - xlReferenceStyle.xlA1
External - True to return an external reference, default is false
RelativeTo - Range representing a relative to cell. Only relevant when ReferenceStyle = xlR1C1


Range.AddressLocal

This is similar to Address but it returns the address in the regional format of the language of the particular country.

Cells.Replace SearchFormat:=True, ReplaceFormat:=True 
lLastRowNo = ActiveCell.End(xlDown).Row

Moving large amounts of data quickly

Dim vArray As Variant 

vArray = Range("A1").Resize(10,10)
Range("H6").Resize(10,10) = vArray

Obtaining the cell reference of the active cell

Dim lrownumber As Long 
Dim icolumnno As Integer

lrownumber = ActiveCell.Row
icolumnno = ActiveCell.Column
Call MsgBox("The currently active cell is " & lrowno & " , " & icolumnno)

Makes the active cell the top left cell in the window

ActiveCell.Select 
ActiveWindow.ScrollColumn = ActiveCell.Column
ActiveWindow.ScrollRow = ActiveCell.Row

Selection

Selection.PasteSpecial Paste:=xlValues 
Selection.Copy
Selection.Cut
Set objRange = Selection
Selection.Rows.Count

Looping through all the selected cells

For Each objCell In Selection.Cells 

Next objCell

Range of cells currently selected

ifirstcol = Range(Selection.Address).Column 
inoofcols = Range(Selection.Address).Column + Selection.Columns.Count
lfirstrow = Range(Selection.Address).Row
lnoofrows = Range(Selection.Address).Row + Selection.Rows.Count
Selection.Font.Size = 12
If TypeName(Selection) = "Range" Then MsgBox("More than one cell currently selected")

Formatting

Call MsgBox( Range("A3").Font.ColorIndex ) 
Call MsgBox( Range("A3").Interior.ColorIndex )
If (Range("A3").Font.ColorIndex < 0) Then Call MsgBox (" When ?")
If (Range("A3").Interior.ColorIndex < 0) Then Call MsgBox (" When ?")
Range("A2").Font.Bold = True
Range("A4:D10").NumberFormat = "mmm-dd-yyyy"

Looping Through Cells

Dim rgeCell As Cell 

For Each rgeCell In Range("A1:D30").Cells
   rgeCell.Value = 20
Next rgeCell
Dim rgeCurrent As Range

Do While Not IsEmpty(rgeCurrent)
'do something
   Set rgeCurrent = rgeCurrent.Offset(1,0)
Loop

You can prevent the user scrolling around a worksheet by defining the scroll area. Worksheets("Sheet1").ScrollArea = "A1:D400". To set the scrolling back to normal just assign the ScrollArea to an empty string. Note that this setting is not saved so it may be necessary to include it in the WorkBook_Open() event procedure.
You can quickly assign an Excel Range of cells to an array and visa-versa. Be aware that these arrays will start at 1 and not 0. vArrayName = Range(---).Value.


Determining a Cell Datatype

Help determine the type of data contained in a cell.
This accepts a range of any size but only operates on the upper left cell in the range.

Function CellType(Rng) 
' Returns the cell type of the upper left
' cell in a range
    Application.Volatile
    Set Rng = Rng.Range("A1")
    Select Case True
        Case IsEmpty(Rng): CellType = "Blank"
        Case Application.IsText(Rng): CellType = "Text"
        Case Application.IsLogical(Rng): CellType = "Logical"
        Case Application.IsErr(Rng): CellType = "Error"
        Case IsDate(Rng): CellType = "Date"
        Case InStr(1, Rng.Text, ":") <> 0: CellType = "Time"
        Case IsNumeric(Rng): CellType = "Value"
    End Select
End Function

Save Shape As PNG

Sub SaveShapeAsPicture() 
Dim cht As ChartObject
Dim ActiveShape As Shape
Dim UserSelection As Variant

  On Error GoTo ErrorHandler
    Set UserSelection = ActiveWindow.Selection
    Set ActiveShape = ActiveSheet.Shapes(UserSelection.Name)

'Create a temporary chart object (same size as shape)
  Set cht = ActiveSheet.ChartObjects.Add( _
    Left:=ActiveCell.Left, _
    Width:=ActiveShape.Width, _
    Top:=ActiveCell.Top, _
    Height:=ActiveShape.Height)

'Format temporary chart to have a transparent background
  cht.ShapeRange.Fill.Visible = msoFalse
  cht.ShapeRange.Line.Visible = msoFalse
    
'Copy/Paste Shape inside temporary chart
  ActiveShape.Copy
  cht.Activate
  ActiveChart.Paste
   
'Save chart to User's Desktop as PNG File
  cht.Chart.Export Environ("USERPROFILE") & "\Desktop\" & ActiveShape.Name & ".png"

'Delete temporary Chart
  cht.Delete

'Re-Select Shape (appears like nothing happened!)
  ActiveShape.Select

Exit Sub
ErrorHandler:
End Sub

Save Range as JPG

Sub SaveRangeAsPicture() 
Dim cht As ChartObject
Dim ActiveShape As Shape

  On Error GoTo ErrorHandler
'Confirm if a Cell Range is currently selected
  If TypeName(Selection) <> "Range" Then
    MsgBox "You do not have a single shape selected!"
    Exit Sub
  End If

'Copy/Paste Cell Range as a Picture
  Selection.Copy
  ActiveSheet.Pictures.Paste(link:=False).Select
  Set ActiveShape = ActiveSheet.Shapes(ActiveWindow.Selection.Name)
  
'Create a temporary chart object (same size as shape)
  Set cht = ActiveSheet.ChartObjects.Add( _
    Left:=ActiveCell.Left, _
    Width:=ActiveShape.Width, _
    Top:=ActiveCell.Top, _
    Height:=ActiveShape.Height)

'Format temporary chart to have a transparent background
  cht.ShapeRange.Fill.Visible = msoFalse
  cht.ShapeRange.Line.Visible = msoFalse
    
'Copy/Paste Shape inside temporary chart
  ActiveShape.Copy
  cht.Activate
  ActiveChart.Paste
   
'Save chart to User's Desktop as PNG File
  cht.Chart.Export Environ("USERPROFILE") & "\Desktop\" & ActiveShape.Name & ".jpg"

'Delete temporary Chart
  cht.Delete
  ActiveShape.Delete

'Re-Select Shape (appears like nothing happened!)
  ActiveShape.Select

Exit Sub
ErrorHandler:
End Sub

Activate vs Select

There is a difference between activating a range and selecting a range.
The following means that the cells "A1:D4" are selected and since "B2" is contained in the cell range "A1:D4" it is the active cell within a larger selection.

Range("A1:D4").Select 
Range("B2").Activate

The following means that the cells "A1:D4" are selected but since "D6" is not contained in cell range "A1:D4", the cell "D6" is then selected.

Range("A1:D4").Select 
Range("D6").Activate

Both methods can only be used to select cells on the active worksheet.


Range to Array

The quickest way to populate an array with values in a cell range is to use a simple Variant data type.
You do not need to define the size of the array before it is populated.
This is only possible when the variable is defined as a Variant.

The array will always be 2 dimensional, it starts at 1 (not 0) and is always rows then columns.


Rows and Columns:

Dim arMyArray As Variant 
arMyArray = Range("A1:D5").Value

One Row:

Dim arMyArray As Variant 
arMyArray = Range("A1:D1").Value

One Column:

Dim arMyArray As Variant 
arMyArray = Range("A1:A5").Value

Array to Range

The quickest way to populate a range with the contents of an array is to define the Value equal to the array.


Rows and Columns:
If you have a 2 dimensional array that you want to display on a worksheet you can assign the array to a Range.Value.
If the array has been populated with (rows, columns) the array can be assigned as it is.

Dim arValues As Variant 
ReDim arValues(1 To 2, 1 To 3)
arValues(1, 1) = "r1,c1"
arValues(1, 2) = "r1,c2"
arValues(1, 3) = "r1,c3"

arValues(2, 1) = "r2,c1"
arValues(2, 2) = "r2,c2"
arValues(2, 3) = "r2,c3"

Range("A1:C2").Value = arValues

This will create the following table.

If the array has been populated with (columns, rows) the array needs to be transposed first.

Dim arValues As Variant 
ReDim arValues(1 To 3, 1 To 2)
arValues(1, 1) = "c1,r1"
arValues(1, 2) = "c1,r2"

arValues(2, 1) = "c2,r1"
arValues(2, 2) = "c2,r2"

arValues(3, 1) = "c3,r1"
arValues(3, 2) = "c3,r2"

arValues = Application.WorksheetFunction.Transpose(arValues)
Range("A1:C2").Value = arValues

This will create the following table.


One Row:
Note that this will create a horizontal array that will populate a row across the worksheet.

Dim arValues As Variant 
arValues = VBA.Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)
Range("A1:L1").Value = arValues

This will create a table across the worksheet.


One Column:
If you want to create a vertical array that will populate a column down the worksheet then you must transpose the array before assigning it to the Range.

Dim arValues As Variant 
arValues = VBA.Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)
arValues = Application.WorksheetFunction.Transpose(arTesting)
Range("A1:A12").Value = arValues

This will create a table down the worksheet.


Empty Value

Dim aMyArray As Variant 
aMyArray = Range("A1").Value

aMyArray has a value Empty if cell "A1" is empty

aMyArray = Range("A1").Value 

aMyArray has the value if cell "A1" contains a value


Row and Column Vectors

Dim aMyArray As Variant 
aMyArray = Range("A1:B1") 'row vector
aMyArray(1,1) = 1
aMyArray(1,2) = 2

Dim aMyArray As Variant 
aMyArray = Range("A1:A2") 'column vector
aMyArray(1,1) = 1
aMyArray(2,1) = 2

Transposing the Array

VBA > Arrays > Transposing


Remember

Excel reads FROM ranges a lot faster than it writes TO ranges.


Value or Value2

The Value2 property does not recognise (and convert into) the VBA Currency data type or the VBA Date data type.
The difference between these two properties is best explained with a simple example.
Enter the number 100 into the cells "C2", "C3" and "C4" and apply the corresponding formatting.


Using Excel Number Format

Cell "C2" has been formatted using the number format "#,##0.00".
Run the following code and when you get to the Stop statement open the Watches window and the Immediate window.

Call ValueOrValue2("C2") 

Public Sub ValueOrValue2(ByVal sAddress As String)
   Dim vCell_value As Variant
   Dim vCell_value2 As Variant
   vCell_value = Range(sAddress).Value
   Debug.Print vCell_value
   vCell_value2 = Range(sAddress).Value2
   Debug.Print vCell_value2
   Stop
End Sub

Notice that the Type for both these local variables is "Variant/Double".


Using Excel Currency Format

Cell "C3" has been formatted using the currency format "£#,##0.00".
Run the following code and when you get to the Stop statement open the Watches window and the Immediate window.

Call ValueOrValue2("C3") 

Notice that the Type for the "Value" property is "Variant/Currency".
And the Type for the "Value2" property is still "Variant/Double".
When you use the "Value2" property in conjunction with cells formatted as Currency they will be recognised as a Double and not as a Currency.
The VBA Currency data type stores numbers as a fixed point number.
If you have numbers that have more than 4 decimal places then using "Value2" will be more accurate.


Using Excel Date Format

Cell "C4" has been formatted using the date format "dd/mm/yyyy".
Run the following code and when you get to the Stop statement open the Watches window and the Immediate window.

Call ValueOrValue2("C4") 

Notice that the Type for the "Value" property is "Variant/Date". This corresponds to what is displayed in the Immediate window.
And the Type for the "Value2" property is still "Variant/Double".
When you use the "Value2" property in conjunction with cells formatted as Dates they will be recognised as a Double and not as a Date..
The VBA Date data type stores numbers as decimal.
The only time it makes sense to use .Value instead of .Value2 is if you want to detect a date in a cell using the VBA.IsDate() function.

Dim vCell As Variant 
vCell = Range("A1").Value
'This creates a sub type of Date which can be detected by the VBA.IsDate function
If (VBA.IsDate(vCell) = True) Then
End If

If you use Value2 in the above example then a date will be converted to a Double data type which is not recognised by the VBA.IsDate function.
Value has an optional parameter of type xlRangeValueDataType
If you pass in Value(xlRangeValueDataType.xlRangeValueDefault) you will get back an object representing the value of the cell.
Both of these methods will return an array if the Range contains multiple cells.

Range("D3").Value2 = Range("A3").Value2 + Range("C7").Value2 

Entering data on the active worksheet

If you want to enter data onto the active worksheet then you can use any of the following.

ActiveSheet.Range("D3").Value = "some text" 
ActiveSheet.Cells(3,4).Value = 200
Range("D3").Value = "some text"
Range("A2").Value = Range("B4").Value + 20
Cells(7,2).Value = 25

This enters the number 60 into all the cells in the range "A1:B10".

Range("A1:B10").Value = 60 

This enters the number 18 into the four cells "A1", "B1", "C1" and "D1".

Range("A1,B1,C1,D1").Value = 18 

This enters the number 5 in all the cells that are the intersection of the two ranges.

Range("A1:B10 A1:D10").Value = 5 

Entering data on a different worksheet

It is good practice to always qualify the worksheet, whether it is the active worksheet or a different worksheet.

Worksheets("Sheet1").Range("A2").Value = 20 
Sheets("Sheet1").Range("B2").Value = 30
Sheets(2).Cells(3,3).Text = "some text"

Remember the difference between "Worksheets" and the "Sheets" collection.
The "Sheets" collection includes all sheets, including Chart sheets.


ActiveCell

The ActiveCell is always a single cell and is the cell that contains the cell pointer.
This property always refers to the active worksheet or window.
If you select several cells on a worksheet, then these cells are considered a selection. One of these cells is the active cell.
A cell does not have to be active in order for it to be edited.
Trying to obtain a reference to the ActiveCell will fail if a Chart Sheet is currently active.

Dim objCell As Range 

Set objCell = Application.ActiveCell
Set objCell = ActiveWindow.ActiveCell
Set objCell = ActiveCell

If a range of cells is selected, the active cell will be in one of the corners and will depend on how the range was selected.
ActiveCell returns Nothing if no worksheet is displayed in the active window.


Selection

The Selection property will references whatever is currently selected in the active workbook.
This could be a Range, Shape, Chart, anything

Application.Selection 
Selection

RangeSelection

This refers to the selected cells on the worksheet in the specified window, even when a graphic object is selected.
This property applies to a Window object.

ActiveWindow.RangeSelection 

This can be useful when you want to refer to the range that was selected before a non-range object was selected.


Using the Cells collection

A common way to refer to particular cells on a worksheet is to use the Cells property.
This enters the number 10 into cell "B2" on the active worksheet.

ActiveSheet.Cells(rowindex, columnindex).value = 10 
ActiveSheet.Cells(2, 2).Value = 10

You can also use the Cells property to refer to a particular cell on a worksheet or in a range
Cells are numbered starting at the left and continuing to the right and then down to the next row.

ActiveSheet.Cells(500).Value = 10 

Removing Data

Using the ClearContents method, removes just the value from a cell and not the cell formatting.

Sheets("Sheet1").Cells.ClearContents 
Range("C1:E6").ClearContents

Sorting Data

more info


Selecting Individual Cells

Cannot select a cell unless that particular worksheet is displayed/active
If using the notation Range("An") is not convenient you can use Cells(rows,columns) instead.
The row and column indexes both start at 1 for Cells(row, column)
It is also possible to use the GoTo dialog box.

Range("B1").Select 

Cells(RowIndex, ColumnIndex).Select
Cells(1, 2).Select
Cells(1, "B").Select 'not guaranteed ???

Application.GoTo

This is comparable to the select method except the range is passed as a parameter
If the range is on another worksheet then that worksheet will be automatically selected.
GoTo is a method that causes Excel to select a range of cells and activate the corresponding workbook.
It takes an optional Object parameter (either String or Range).
It also takes an optional second Object parameter that can be set to True to indicate if you want Excel to scroll the window so that the selection is in the top-left corner.

Application.GoTo Range("B3") 
Application.GoTo Reference:=Range("A2")
Application.GoTo ("R3C2")
Application.GoTo ("Sheet1!R3C2")
Application.GoTo (Range("A2"),True)
Application.GoTo (Range("A2","B3"),True)

This is also has an optional scrolling parameter ??
The following line of code is not allowed.

Range(Cells(2,3)).Select 

Selecting a Range (or Multiple Cells)

Range("A1:D4").Select 
Range("A1", "D4").Select 'This is exactly the same as the above line
Range("A1,D4").Select 'This selects just the 2 cells

Range("A1", "G3").Select
Range("B1:C10").Select
Range("A1:B2, C3:D4").Select
Range("A1:B4", "D3:G6").Select
Range( Cells(2,3), Cells(5,6) ).Select
Worksheets("Sheet3").Range("A1:B10, C2:D40").Select
Application.Intersect(Range("A2"), Range("D10"))
Range("C1:C10 A6:E6").Select
Application.Union(Range("A1:G10"), Range("B6:D15"))

You can also use the following abbreviation although it is not recommended:

Range("A1:B3").Select 
[A1:B3].Select

Selecting the whole worksheet

ActiveSheet.Cells.Select 

Selecting a Different worksheet

The following line of code will not work unless Sheet1 is currently selected.

Worksheets("Sheet1").Range("A2").Select 

You must select the worksheet first and then select the range.


Selecting using the Current Selection

Using the Selection object performs an operation on the currently selected cells.
If a range of cells has not been selected prior to this command, then the active cell is used.

Selection 

Selecting using the Active Cell

The ActiveCell is often used and refers to the cell that is currently selected.
You can also easily obtain the cell address of the active cell.

ActiveCell.End(xlDirection.xlDown).Select 
Call MsgBox( ActiveCell.Column & ActiveCell.Row )

Selecting the CurrentRegion or UsedRange

The CurrentRegion property setting consists of a rectangular block of cells surrounded by one or more blank rows or columns.
The UsedRange is the range of all non-empty cells.

ActiveSheet.ActiveCell.CurrentRegion.Select 
ActiveSheet.UsedRange.Select

Selecting using Relative References

You can use the Range property of a Range object to create a relative reference to the Range object (e.g. Range("C3").Range("B2") = D4).
If you are using Range("A4".Cells(2,2)) to obtain a relative reference it is marginally faster to use Range("A4")(2,2).

Range("A2").End(xlDirection.xlDown).Select 
Range("A1:D10").Cells(6).Select

Selecting Rows and Columns

Range("C:C").Select 
Range("7:7").Select
Range("2:2,4:4,6:6").Select
Range("A;A,C;C,E;E").Select

Range.SpecialCells Method

This method returns a range that represents all the cells that match a particular criteria

Range.SpecialCells(Type, Value) 

Type - The type of cells to select from the xlCellType enumeration.
Value - This is an additional argument that is required when Type is xlCellTypeConstants or xlCellTypeFormulas.
The default is to select all constants and formulas.

objBlankCells = Selection.SpecialCells(Type:=xlCellType.xlCellTypeBlanks) 

The following line selects the last "used" cell on the worksheet

ActiveSheet.Cells.SpecialCells(Type:=xlCellType.xlCellTypeLastCell) 

xlCellTypeConstants or xlCellTypeFormulas.

Using this method will generate an error if there are no cells currently selected.
The following line creates a subset range containing all the cells that contain formulas.

objFormulaCells = Selection.SpecialCells(Type:=xlCellType.xlCellTypeFormulas, _ 
                                         Value:=xlSpecialCellsValue.xlNumbers)

The following line creates a subset range containing all the cells that contain constants

objConstantCells = Selection.SpecialCells(Type:=xlCellType.xlCellTypeConstants, _ 
                                          Value:=xlSpecialCellsValue.xlNumbers)

The following line clears all constants from a worksheet

objWorksheet.Cells.SpecialCells(Type:=xlCellType.xlCellTypeConstants, _ 
                                Value:=xlSpecialCellsValue.xlNumbers).ClearContents

Selecting all non blank cells on a sheet

Public Sub AllNonBlank() 
   Application.Union(ActiveSheet.Cells.SpecialCells(Type:=xlCellType.xlCellTypeFormulas,
                                                    Value:=xlSpecialCellsValue.xlErrors + _
                                                           xlSpecialCellsValue.xlLogical + _
                                                           xlSpecialCellsValue.xlNumbers + _
                                                           xlSpecialCellsValue.xlTextValues), _
                     ActiveSheet.Cells.SpecialCells(Type:=xlCellType.xlCellTypeConstants, _
                                                    Value:=23)).Select
End Sub

Selecting all cells in a range that contain an error

This will select any cells that contain: #CALC!, #DIV/0, #FIELD!, #N/A, #NAME?, #NULL!, #NUM!, #REF!, #SPILL!, #VALUE!.

Public Sub CellsWithErrors 
   Range("A1:A16385").SpecialCells(xlCellType.xlCellTypeFormulas, xlSpecialCellsValue.xlErrors).Select
End Sub

KeyStroke Equivalents

The macro recorder does not record any keystrokes you use to select a range of cells.
This line of code is equivalent to pressing (Ctrl + Shift + 8).

ActiveCell.CurrentRegion.Select 

Multiple Selected Ranges

A Range object can comprise of multiple separate ranges.
Most properties and methods that refer to a range object take into account only the first rectangular area of the range.
You can use the Areas property to determine if a range contains multiple areas

If (Selection.Areas.Count > 1) Then 
End If

Excel will actually allow multiple selections to be identical.
You can hold down the Ctrl and click cell "A1" five time.
The selection will have five identical areas.


Protecting Cells

This just prevents the cells from being edited

Dim objRange As Excel.Range 

If (objRange.Locked = True) Then
'all cells in range are locked
End If

If (objRange.Locked = False) Then
'all cells in range are not locked
End If

If (objRange.Locked = null) Then
'cells in range have a combination of locked and unlocked
End If

GoTo Dialog

If Type is either xlCellTypeConstants or xlCellTypeFormulas, this argument is used to determine which types of cells to include in the result.
These values can be added together to return more than one type.
The default is to select all constants or formulas, no matter what the type.


Comments

ActiveSheet.Cells.SpecialCells(Type:=xlCellType.xlCellTypeComments).Select 
Selection.SpecialCells(xlCellType.xlCellTypeComments).Select

Constants

Selection.SpecialCells(xlCellType.xlCellType.Constants, 23).Select 
ActiveSheet.Cells.SpecialCells(Type:=xlCellType.xlCellTypeConstants, _
                               Value:=xlSpecialCellsValue.xlNumber).Select

Formulas

Selection.SpecialCells(xlCellType.xlCellTypeFormulas,3).Select 
ActiveSheet.Cells.SpecialCells(Type:=xlCellType.xlCellTypeFormulas, _
                               Value:=xlSpecialCellsValue.xlNumber).Select

Blanks

Selection.SpecialCells(xlCellType.xlCellTypeBlanks).Select 

CurrentRegion

Selection.CurrentRegion.Select 

CurrentArray

Selection.CurrentArray.Select 

Objects

ActiveSheet.DrawingObjects.Select 

Row Differences

Selection.RowDfferences(ActiveCell).Select 

Column Differences

Selection.ColumnDifferences(ActiveCell).Select 

Precedents

Selection.DirectPrecedents 

Dependents

Selection.DirectDependents 

Last Cell

Selection.SpecialCells(xlCellType.xlCellTypeLastCell).Select 

Visible Cells Only

Selection.SpecialCells(xlCellType.xlCellTypeVisible).Select 

Conditional Formatting

ActiveCell.SpecialCells(xlCellType.xlCellTypeAllFormatConditions).Select 

Data Validation

ActiveCell.SpecialCells(xlCellType.xlCellTypeAllValidation).Select 

Application.Intersect

Returns a Range object that represents the rectangular intersection of two or more ranges.


This example selects the intersection of two named ranges, rg1 and rg2, on Sheet1. If the ranges don't intersect, the example displays a message.

Worksheets("Sheet1").Activate 
Set isect = Application.Intersect(Range("rg1"), Range("rg2"))
If isect Is Nothing Then
    MsgBox "Ranges do not intersect"
Else
    isect.Select
End If

Application.Union

Returns the union of two or more ranges.
This example fills the union of two named ranges, Range1 and Range2, with the formula =RAND().

Worksheets("Sheet1").Activate 
Set bigRange = Application.Union(Range("Range1"), Range("Range2"))
bigRange.Formula = "=RAND()"

Sub Testing_Selection() 
Dim lrowno As Long
Dim icolno As Integer
Dim objObject As Excel.Application
Dim iareatotal As Integer
Dim iareacount As Integer
Dim objFinalSelection As Excel.Range
Dim objUnionSelection As Excel.Range
Dim objcellfirst As Excel.Range
Dim objcellstartofrow As Excel.Range
Dim objSelection As Excel.Range

Set objObject = Application

    objObject.Range("C4:F15").Select
    objObject.Selection.FormulaArray = "=RAND()"

    Set objUnionSelection = objObject.Range("E10")
    Set objUnionSelection = Union(objUnionSelection, objObject.Range("F13"))
    objUnionSelection.Select

Set objSelection = objObject.Selection
iareatotal = objSelection.Areas.Count

For iareacount = 1 To iareatotal

lrowno = objSelection.Areas(iareacount).Row
icolno = objSelection.Areas(iareacount).Column

Set objcellfirst = objObject.Cells(lrowno, icolno)
Set objcellstartofrow = objSelection.Areas(iareacount).
            Offset(0, objObject.Cells(lrowno, icolno).CurrentRegion.Column - icolno)
Set objFinalSelection = objcellstartofrow.Resize(
             objSelection.Areas(iareacount).Rows.Count, objcellfirst.CurrentRegion.Columns.Count)

If iareacount = 1 Then
Set objUnionSelection = objFinalSelection
Else
Set objUnionSelection = Union(objUnionSelection, objFinalSelection)
End If

Next iareacount

objUnionSelection.Select
End Sub

Inserting Cells

Range("B2:F5").Insert(xlInsertShiftDirection.xlShiftDown) 
Range("B2:F5").Insert(xlInsertShiftDirection.xlShiftToRight)

Deleting Cells

This deletes the cells in the range "B2:F2".

Range("B2:F5").Delete(xlDeleteShiftDirection.xlShiftUp) 
Range("B2:F5").Delete(xlDeleteShiftDirection.xlShiftToLeft)

If the Shift argument is omitted then Excel will guess the best direction based on the shape of the range.


Clearing Data

ActiveCell.CurrentRegion.ClearContents 

Selection.Delete

Even with displayalerts = false you will get the following prompt if the selection currently has a filter applied to it.
SS
Delete entire row ?


Cutting and Pasting ranges of cells

You can cut and paste a single value using either of the following lines of code:

Range("A2").Cut Destination:=Range("D2") 
Range("A2").Cut Range("D2")

The Cut method also has an optional destination argument.
It is possible to cut and paste a range of cells:

Range("A2:B4").Select 
Selection.Cut
Range("D7").Select
ActiveSheet.Paste

Alternatively you can combine this to a single line.
This is possible because the Cut method can take an optional argument that can represent the range to be cut to. The next two lines are equivalent.

Range("A2:B4").Cut Destination:=Range("D7") 
Range("A2:B4").Cut Range("D7")

Application.Calculate

If you are manipulating a lot of cells then it is sometimes a good idea to switch the automatic calculation off temporarily

Application.Calculate = xlCalculation.xlCalculationManual 
'manipulating a lot of cells
Application.Calculate = xlCalculation.xlCalculationAutomatic

Copying

Excel > Charts > VBA Code > Copying
Excel > Illustrations > VBA Code > Copying
Word > Paragraphs > VBA Code


Copying and Pasting a single value

The most intuitive way to copy data from one cell to another would be:

Range("A2").Select 
Selection.Copy
Range("D2").Select
ActiveSheet.Paste

One of the most important aspects of VBA programming is remembering that you do not have to actually select the object you want to manipulate.
The code could therefore be changed to the following.

Range("A2").Copy 
Range("D2").Select
ActiveSheet.Paste

There are always several ways to accomplish the same thing in VBA.
The code could be reduced to two lines using the Paste Special method.

Range("A2").Copy 
Range("D2").PasteSpecial Paste:=xlValues

It is actually possible to condense this action into a single line.
This is possible because the Copy method can take an optional argument that can represent the range to be copied to. The next two lines are equivalent.

Range("A2").Copy Destination:=Range("D2") 
Range("A2").Copy Range("D2")

This copies the contents of cell "D2" and places them into the active cell.

Range("D2").Copy Destination:=ActiveCell    

Copying Data between Worksheets

It is possible to copy data between worksheets.
The can be done by including a reference to a particular worksheet. If no worksheet is specified then the active worksheet is used.

Worksheets("Sheet1").Range("A2").Copy Worksheets("Sheet2").Range("D2") 

Notice that you do not have to activate the necessary worksheets.
The following line of code copies the whole block of data to a worksheet Sheet2.

Range("A2").CurrentRegion.Copy Sheets("Sheet2").Range("D2") 

Copying Data between Workbooks

It is possible to copy data between worksheets.
The can be done by including a reference to a particular worksheet. If no worksheet is specified then the active worksheet is used.

Workbooks("Wbk1.xls".Worksheets("Sheet1").Range("A2").Copy Workbooks("Wbk2.xls").Worksheets("Sheet2").Range("D2") 

Long lines of code can sometimes be difficult to understand.
Another way to perform the same task is to use variables to store the necessary range objects.

Dim rgeCopyRange As Range 
Dim rgeToRange As Range

Set rgeCopyRange = Workbooks("Wbk1.xls").Worksheets("Sheet1").Range("A2")
Set rgeToRange = Workbooks("Wbk2.xls").Worksheets("Sheet2").Range("D2")
rgeCopyRange.Copy rgeToRange

Cancelling the Copy Mode

When you copy (or Cut) a range of cells a black dotted line appears around the area to help identify it.
This can be removed by switching the CutCopy property to False.

Application.CutCopyMode = xlCutCopyMode.False 

If you do not change this property back to false then the cell range that was last copied will remain flashing on the screen.

Range("A2").Copy 
Range("D2").Select
ActiveSheet.Paste
Application.CutCopyMode = xlCutCopyMode.False

You do not need to reset this property if you use a single line statement to copy and paste.

Range("A2").Copy Range("D2") 

Copying Ranges as Pictures

to copy the selected worksheet range as a picture

Selection.CopyPicture Appearance:=xlPictureAppearance.xlScreen, Format:=xlCopyPictureFormat.xlPicture 

Freeze and unfreeze references when copying

Public arFormulas() As Variant 

Public Sub Freeze()
    arFormulas = Selection.Formula
End Sub

Public Sub UnFreeze()
    If (Not Not arFormulas) = 0 Then
        Call MsgBox ("Error: No formulas were copied. Please use the Freeze routine first.")
        Exit Sub
    End If

    Selection.Resize(UBound(arFormulas, 1), UBound(arFormulas, 2)).Value = arFormulas
End Sub


Paste Special - Range Object

Pastes a Range from the Clipboard into the specified range.

Range("A1").PasteSpecial Paste:=xlPasteType.xlPasteValues, _ 
                         Operation:=xlPasteSpecialOperation.xlPasteSpecialOperationAdd, _
                         SkipBlanks:=False, _
                         Transpose:=False

Paste - The part of the range to be pasted.
Operation - The paste operation.
SkipBlanks - Whether to have blank cells in the range on the Clipboard not be pasted into the destination range. The default value is False.
Transpose - Whether to transpose rows and columns when the range is pasted. The default value is False.


Paste Special - Worksheet Object

Pastes the contents of the Clipboard onto the sheet, using a specified format. Use this method to paste data from other applications or to paste data in a specific format.
You must select the destination range before you use this method. This method may modify the sheet selection, depending on the contents of the Clipboard.

ActiveSheet.PasteSpecial Format:="Text", _ 
                         Link:=True | False, _
                         DisplayAsIcon:=True | False, _
                         IconFileName:="C:\Temp\icon.bmp", _
                         IconIndex:=1, _
                         IconLabel:="Text label", _
                         NoHTMLFormatting:=True | False

All the parameters are optional
Format - A string that specifies the Clipboard format of the data. msoClipboardFormat ?
Link - Whether to establish a link to the source of the pasted data. If the source data isn't suitable for linking or the source application doesn't support linking, this parameter is ignored. The default value is False.
DisplayAsIcon - Whether to display the pasted as an icon. The default value is False.
IconFileName - The name of the file that contains the icon to use if DisplayAsIcon is True.
IconIndex - The index number of the icon within the icon file.
IconLabel - The text label of the icon.
NoHTMLFormatting - Whether to remove all formatting, hyperlinks, and images from HTML. False to paste HTML as is. The default value is False. NoHTMLFormatting will only matter when Format = "HTML". In all other cases, NoHTMLFormatting will be ignored.


ActiveSheet.PasteSpecial Format:="Text" 
ActiveSheet.PasteSpecial Format:="HTML"
ActiveSheet.PasteSpecial Format:="Microsoft Word 8.0 Document Object"

This example pastes a Word document object and displays it as an icon.

Worksheets("Sheet1").Range("F5").Select 
ActiveSheet.PasteSpecial Format:="Microsoft Word 8.0 Document Object", _
                         DisplayAsIcon:=False,


Paste - Worksheet Object

Pastes the contents of the Clipboard onto the sheet.
If you don't specify the Destination argument, you must select the destination range before you use this method.
This method may modify the sheet selection, depending on the contents of the Clipboard.

Worksheets("Sheet1").Range("C1:C5").Copy 
ActiveSheet.Paste Destination:=Worksheets("Sheet1").Range("A2"), _
                  Link:=False

Destination - A Range object that specifies where the Clipboard contents should be pasted. If this argument is omitted, the current selection is used. This argument can be specified only if the contents of the Clipboard can be pasted into a range. If this argument is specified, the Link argument cannot be used.
Link - Whether to establish a link to the source of the pasted data. If this argument is specified, the Destination argument cannot be used. The default value is False.


Pasting into Word

Paste as a Windows Metafile
Only pastes in colour if there is a colour printer selected ??

Word.Selection.PasteSpecial Link:=False, _ 
                            DataType:=wdPasteDataType.wdPasteEnhancedMetafile, _
                            Placement:=0, _
                            DisplayAsIcon:=False

Word > Paragraphs > VBA Code
wdPasteMetafile
doesn't matter what the zoom % is.
image is automatically resized to fit the width of the page.


Selection.PasteAndFormat (Word.wdRecoveryType.wdSingleCellText) 

Pasting into PowerPoint

link - pptfaq.com/FAQ00826.htm 

Excel > EMF > Word - wdPasteMetafile % is wrong
Excel > EMF > Word - wdPasteOLEObject % is right - creates a copy of workbook and embeds it into the word document.


cell range - create a picture of the range to get the size


CopyPicture option


Copy, Save Picture and Send

This copies a cell range, saves it as a picture and adds it to an email.

Public Sub SaveRangeAndSend() 
   Call Cells_ToPicture(Range("A1:B20"), "C:\Temp\myFile.png")
   Call SendEmail("C:\Temp\myFile.png", "myFile.png")
End Sub

This code creates an Outlook email and embeds an image into the email body.
You need to add a reference to the Microsoft Office 16.0 Object Library.

Public Sub SendEmail(ByVal sFullPath As String, _ 
                     ByVal sFileName As String)
Dim oOutlookApp As Outlook.Application
Dim oMailItem As Outlook.MailItem

    Set oOutlookApp = CreateObject("Outlook.Application")
    Set oMailItem = oOutlookApp.CreateItem(OlItemType.olMailItem)
    
    With oMailItem
        .Subject = "mytitle"
        .HTMLBody = "add some text

<IMG src=""cid:" & sFileName & """>"
        .Recipients.Add "myname@bettersolutions.com"
        .Attachments.Add sFullPath, Type:=OlAttachmentType.olEmbeddeditem, Position:=0
    End With
    
    oMailItem.Display
'oMailItem.Send
   Exit Sub
ErrorHandler:
    MsgBox (Err.Number & " - " & Err.description)
End Sub

Finding Last Row Column

The only way to accurately determine the next (or last row) that contains data is to check every cell using ActiveCell.Offset(1,0).
There are a number of alternatives, but most of them rely on the "UsedRange" property being updated.
Deleting rows or columns (or content that should impact the UsedRange) will not be reflected unless the UsedRange is reset.


Using Ctrl + End

Moves the selection from the active cell to the last used cell on the worksheet.
Cells that have been formatted (but contain no values) are considered "used".
This relies on the "UsedRange" property being reset.


Using UsedRange

One of the most common ways to find the last cell on a worksheet is to use the UsedRange property.
The "UsedRange" property can be reset either by saving the workbook or running code that uses the "UsedRange" property.

Dim llastrow As Long 
Dim llastcolumn As Long

llastrow = ActiveSheet.UsedRange.Row + ActiveSheet.UsedRange.Rows.Count - 1
Debug.Print llastrow

llastcolumn = ActiveSheet.UsedRange.Column + ActiveSheet.UsedRange.Columns.Count - 1
Debug.Print llastcolumn

When you have a "clean" worksheet the following code returns the correct last cell "E4".

However this property does not just include cells that contain actual data but also any cells that have been formatted.
For example if we run the same code on the following worksheet the last cell is "F5".


Using SpecialCells(xlCellTypeLastCell)

This is the equivalent of using Ctrl+End and therefore also relies on the "UsedRange" property.
The same is true for the xlCellTypeLastCell argument which can be used with the SpecialCells property.

llastrow = Range("A1").SpecialCells(XlCellType.xlCellTypeLastCell).Row 
Debug.Print llastrow

llastcolumn = Range("A1").SpecialCells(XlCellType.xlCellTypeLastCell).Column
Debug.Print llastcolumn

This also includes formatting in the range that is returned.
The xlLastCell constant is not documented because this constant was replaced in Excel 97 with the new xlCellType.xlCellTypeLastCell.
The following line of code does work but has only been included for backwards compatibility reasons.

llastrow = Range("A1").SpecialCells(xlLastCell).Row 

The macro recorder will generate code with the xlLastCell constant which adds to the confusion.


Using Cells.Find

Another popular approach which can be used to obtain the last "populated" row and column is to use the Cells.Find method.
This method searches backwards first by row and then by column from the top left cell.
The last row is the last visible row taking Filtering into account, but is not impacted by Manually Hidden Rows or collapsed Grouping.
The last column is the last visible column taking Manually Hidden Columns into account, but is not impacted by collapsed Grouping.

llastrow = ActiveSheet.Cells.Find(What:="*", _ 
                                  After:=ActiveSheet.Range("A1"), _
                                  SearchOrder:=XlSearchOrder.xlByRows, _
                                  SearchDirection:=XlSearchDirection.xlPrevious).Row
Debug.Print llastrow

Dim oRange As Range
Set oRange = Range("A1:E200")
llastrow = oRange.Find(What:="*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
Debug.Print llastrow

llastcolumn = ActiveSheet.Cells.Find(What:="*", _
                                     After:=ActiveSheet.Range("A1"), _
                                     SearchOrder:=XlSearchOrder.xlByColumns, _
                                     SearchDirection:=XlSearchDirection.xlPrevious).Column
Debug.Print llastcolumn

llastcolumn = oRange.Find(What:="*", SearchOrder:=xlByColumns, SearchDirection:=xlPrevious).Column
Debug.Print llastcolumn

Using End(xlUp)

Use the following to obtain the address of the last non-empty cell in column "A".
The last row is the last visible row taking into account Filtering, Manually Hidden Rows and collapsed Grouping.

llastrow = Range(Range("A65536").End(xlDirection.xlUp).Address).Row 
llastrow = Range("A" & Rows.Count).End(xlUp).Row
Debug.Print llastrow

Last Column in a Range

Use the following to obtain the last column in a range.

Dim oRange As Range 
Set oRange = Range("A1:E200")
llastcolumn = oRange(oRange.Rows.Count, oRange.Columns.Count).Column
Debug.Print llastcolumn

Application.GoTo

Selects any range or Visual Basic procedure in any workbook, and activates that workbook if it's not already active.
expression.Goto(Reference, Scroll)
Reference Optional Variant. The destination. Can be a Range object, a string that contains a cell reference in R1C1-style notation, or a string that contains a Visual Basic procedure name. If this argument is omitted, the destination is the last range you used the Goto method to select.
Scroll Optional Variant. True to scroll through the window so that the upper-left corner of the range appears in the upper-left corner of the window. False to not scroll through the window. The default is False.
This method differs from the Select method in the following ways:
     ● If you specify a range on a sheet that's not on top, Microsoft Excel will switch to that sheet before selecting. (If you use Select with a range on a sheet that's not on top, the range will be selected but the sheet won't be activated).
     ● This method has a Scroll argument that lets you scroll through the destination window.
     ● When you use the Goto method, the previous selection (before the Goto method runs) is added to the array of previous selections (for more information, see the PreviousSelections property). You can use this feature to quickly jump between as many as four selections.
     ● The Select method has a Replace argument; the Goto method doesn't.
This example selects cell A154 on Sheet1 and then scrolls through the worksheet to display the range.

Application.Goto Reference:=Worksheets("Sheet1").Range("A154"),     scroll:=True 

Range.Find Method

Finds specific information in a range, and returns a Range object that represents the first cell where that information is found.
Returns Nothing if no match is found. Doesn't affect the selection or the active cell.
The settings for LookIn, LookAt, SearchOrder, and MatchByte are saved each time you use this method.
If you don't specify values for these arguments the next time you call the method, the saved values are used.
Setting these arguments changes the settings in the Find dialog box, and changing the settings in the Find dialog box changes the saved values that are used if you omit the arguments.
To avoid problems, set these arguments explicitly each time you use this method.
You can use the FindNext and FindPrevious methods to repeat the search.


When the search reaches the end of the specified search range, it wraps around to the beginning of the range. To stop a search when this wraparound occurs, save the address of the first found cell, and then test each successive found-cell address against this saved address.
To find cells that match more complicated patterns, use a For Each...Next statement with the Like operator. For example, the following code searches for all cells in the range A1:C5 that use a font whose name starts with the letters "Cour". When Microsoft Excel finds a match, it changes the font to Times New Roman.


Finding any matching values

When searching a large range of cells it is significantly faster to search a column and spin down the rows as opposed to a row and spin through all the columns.

Dim rgeRange As Range 

rgeRange = Cells.Find(What:=MyValue)
If Not rgeRange Is Nothing Then
   Cells.Find(What:=MyValue _
              After:=Range("C2"), _
              LookIn:=xlFindLookIn.xlValues, _
              LookAt:=xlLookAt.xlPart, _
              SearchOrder:=xlSearchOrder.xlByRows, _
              SearchDirection:=xlSearchDirection.xlNext, _
              MatchCase:=False).Activate
End If

What - The data you want to search for (String)
After - A single cell representing the cell to start searching from
LookIn - The type of data to search.
LookAt - Whether the search is against the whole string or part of the string.
SearchOrder - The order in which to search the range.
SearchDirection - The search direction when searching a range.
MatchCase - True or False to match the case
MatchByte - True to match double byte characters match only
SearchFormat - True to use the Application.FindFormat options.


Finding and selecting the Maximum Value in a Range

Sub GoToMax 
Dim WorkRange As Range

If TypeName(Selection) <> "Range" Then Exit Sub

If Selection.Cells.Count = 1 Then
'set it to the whole worksheet
   Set WorkRange = ActiveSheet.Cells
Else
   Set WorkRange = Selection
End If

MaxVal = Application.WorksheetFunction.Max(WorkRange)

'find it and select it
On Error Resume Next
WorkRange.Find(What:=MaxVal, _
               After:=WorkRange.Range("A1"), _
               LookIn:=xlValues, _
               LookAt:=xlLookAt.xlPart, _
               SearchOrder:=xlSearchOrder.xlByRows, _
               SearchDirection:=xlSearchDirection.xlNext, _
               MatchCase:=False).Select

If Err <> 0 Then MsgBox("Max value was not found: " & MaxVal)
??

End Sub

Finding any merged cells

Public Sub BET_Find_MergedCells() 
Dim rngCell As Range
Dim stemp As String

   stemp = ""
   For Each rngCell In Selection
      If rngCell.MergeCells = True Then
         stemp = stemp & rngCell.Address & " "
      End If
   Next rngCell
   Call MsgBox(Left(stemp, Len(stemp) - 1))
End Sub

Finding Unique Items

This function will return the unique items in an array. Used to find the unique items in a column of Excel data.

Function UniqueItems(ArrayIn, Optional Count As Variant) As Variant 
' Accepts an array or range as input
' If Count = True or is missing, the function returns the number of unique elements
' If Count = False, the function returns a variant array of unique elements
    Dim Unique() As Variant ' array that holds the unique items
    Dim Element As Variant
    Dim i As Integer
    Dim FoundMatch As Boolean
' If 2nd argument is missing, assign default value
    If IsMissing(Count) Then Count = True
' Counter for number of unique elements
    NumUnique = 0
' Loop thru the input array
    For Each Element In ArrayIn
        FoundMatch = False
' Has item been added yet?
        For i = 1 To NumUnique
            If Element = Unique(i) Then
                FoundMatch = True
                GoTo AddItem '(Exit For-Next loop)
            End If
        Next i
AddItem:
' If not in list, add the item to unique list
        If Not FoundMatch Then
            NumUnique = NumUnique + 1
            ReDim Preserve Unique(NumUnique)
            Unique(NumUnique) = Element
        End If
    Next Element
' Assign a value to the function
    If Count Then UniqueItems = NumUnique Else UniqueItems = Unique
End Function

Offset Method

Range.Offset(RowOffset, ColumnOffset)
This method returns range that is offset to a range object.
This method does not change the active range (unlike the Select and Activate methods).
This enters the number 15 in the cell directly below and to the right of the active cell.

ActiveCell.Range("B2").Value = 15 

The preferred method though is to use the Offset property.

ActiveCell.Offset(rowindex, columnindex).Value = 15 
ActiveCell.Offset(1, 1).Value = 15
ActiveCell.Offset(1, -2).Select
Range(ActiveCell.Offset(1). ActiveCell.Offset(1).End(xlDirection.xlDown)).Select
ActiveCell.Offset(0, 1).Value = "some text"

Using the Offset position (0, 0) will refer to the active cell.

ActiveCell.Offset(0, 0).Value = "some text" 
Range("B2").Offset(4, 4).Value = 20

If you try to Offset to a cell which has in invalid column or row number then an error will be generated.


Referring to the Row Above

Range("B2").Offset(1,0).Address = "B1" 
Range("B2").Offset(1).Address = "B1"

Referring to the Row Below

Range("B2").Offset(1,0).Address = "B3" 
Range("B2").Offset(1).Address = "B3"

Referring to the Next Column

Range("B2").Offset(0, 1).Address = "C2" 
Range("B2").Offset(, 1).Address = "C2"

Referring to the Previous Column

Range("B2").Offset(0, 1).Address = "A2" 
Range("B2").Offset(, 1).Address = "A2"

Resize Method

This allows you to alter the size of a range

Range("A1").Resize(2,3) = C2 

expression.Resize(RowSize, ColumnSize)

RowSize - The number of rows in the new range. If this argument is omitted, the number of rows in the range remains the same.
ColumnSize - The number of columns in the new range. If this argument is omitted, the number of columns in the range remains the same.
Both of these arguments are optional and if omitted then the range stays the same.
This example resizes the selection on Sheet1 to extend it by one row and one column.

Worksheets("Sheet1").Activate 
numRows = Selection.Rows.Count
numColumns = Selection.Columns.Count
Selection.Resize(numRows + 1, numColumns + 1).Select

This example assumes that you have a table on Sheet1 that has a header row. The example selects the table, without selecting the header row. The active cell must be somewhere in the table before you run the example.

Set tbl = ActiveCell.CurrentRegion 
tbl.Offset(1, 0).Resize(tbl.Rows.Count - 1, _
    tbl.Columns.Count).Select

or

Dim inoofcolumns As Integer 
Dim lnoofrows as Long

inoofcolumns = ActiveCell.CurrentRegion.Columns.Count
ActiveCell.CurrentRegion.Offset(1,0).Resize(lnoofrows - 1, inoofcolumns).Select

Evaluate Method

You can also use the following abbreviations although they are not encouraged.
This method can be used to generate references to Range objects and also for calculating worksheet formulas.
The normal syntax is as follows:

Application.Evaluate("Expression") 

There are also several shortcut formats to this method as well.

Evaluate("Expression") 

You can also remove the quotes and surround the expression with square brackets.

[Expression] 

Calculating Formulas

The Expression can be any valid worksheet calculation, with or without the equal sign on the left.
The worksheet calculations can include worksheet functions that are not made available to VBA using the WorksheetFunction object.
The worksheet calculations can also be array formulas.
For example the ISBLANK worksheet function is not accessible using WorksheetFunction object because VBA has the equivalent IsEmpty() function.
The following two lines of code are equivalent.

Call MsgBox(Evaluate("=ISBLANK(A1)") 
MsgBox [ISBLANK(A1)]

The advantage of using the first technique is that the worksheet formula string can be generated using code making it more flexible.


Manipulating a Range

The following two lines of code select the range of cells "A1:D4".

Range("A1:D4").Select 
[A1:D4].Select

Application.Evaluate("A4").Value = "some text" 
Evaluate("A4").Value = "some text"
A4.Value = "some text"
[A4].Value = "some text"

This expression could it fact be simplified even more since the default property for a Range object is Value.
Using the default properties is definitely not recommended.

[A4] = "some text" 

You can also use this technique to quickly refer to cells using Named Ranges.

[Named_Range].Select 
[Named_Range] = "some text"

Quick Arrays

The Evaluate method can also be used to quickly obtain an array of numbers.

Dim arValues As Variant 
arValues = Application.Evaluate("Row(1:50)") = {1,2,3, .. 50}

Similarly you can use this technique to quickly insert a sequence of numbers into a range of cells.

Range("B1:B50").Value = Application.Evaluate("Row(1:50)") 

Other Named Objects

Evaluate can also be used with other named objects, such as drawing elements.
It can also be used with Named Ranges.


AutoFill - Filling a Range Down

You do not have to select the cells first

objRange.Auto Fill(Destination:=Range("B2"), _ 
                  Type:=xlAutoFillType.xlFillDefault)

The Destination is the range of cells to be filled. This cell range must include the actual source data in order to create the Auto Fill.
If the Type argument is left blank or you choose xlFillDefault then Excel will attempt to select the most appropriate fill type based on the source data.


Example when cell contains values



Example when cell contains formulas

One potential problem with the Auto Fill method is that when it is executed, the formula in the source cell is copied, with changes to other cells.
However the value of the source cell is also copied, but without changes.
So if autocalculation is switched off, the formulas will be correct but the values will be incorrect.
This can be overcome by invoking a Calculate method after the Auto Fill has been executed.

Application.Calculate 

Filling Down with Values

Fills down from the top cell or cells in the specified range to the bottom of the range.
The contents and formatting of the cell in the top row of a range are copied into the rest of the rows in the range.

Selection.FillDown 

This example copies the contents in cell "A1" down to the whole range "A2:A10".

Range("A1:A10").FillDown 

Filling Down with Formulas

Range("C1").Formula = "=A1+B1" 
Range("C1:C7").FillDown

Restricting the Scroll Area of a worksheet

It is possible to restrict the scroll area of a worksheet by using the ScrollArea property of a worksheet object.
Open the workbook and select the worksheet you want to restrict the scroll area for.
Defining a specific scrollarea though will prevent the user from being able to select the row and column headings.
Display the Control Toolbox toolbar and select the Properties button.
This will display the Properties window for that specific worksheet allowing you to define a scroll area.


Alternatively you could use the following line of VBA code:

Sheets(1).ScrollArea = "A1:H20" 

To reset the scroll area afterwards, set the scroll area back to being the whole worksheet.

Sheets(1).ScrollArea = Sheets(1).Cells.Address 

Any cells outside this area cannot be selected.

Worksheets(1).ScrollArea = "A1:E20" 

Set this property to an empty string to enable cell selection on the entire worksheet.


Hyperlinks

Range("B2").Hyperlinks.Add(Anchor:= 
                    Address:=
                   TextToDisplay:=

Anchor - This can either be a Range or a Shape.
Address - The address of the hyperlink.
SubAddress - The subaddress of the hyperlink
This can be used to create links to cells in the same workbook (eg cells and named ranges)


ScreenTip - The text to display when you hover over with the mouse.
TextToDisplay - The text to display as the hyperlink.


ActiveWorksheet.Hyperlinks.Delete 

ActiveWorkbook.FollowHyperlink 
   Address:="https://bettersolutions.com"
   NewWindow:=True

Removing all Hyperlinks

Public Sub RemoveAllHyperlinks() 
Dim objworksheet As Worksheet
Dim objhyperlink As Hyperlink
Dim lhypercount As Long
Dim answer

'Set objworksheet = Selection.Parent
answer = MsgBox("Do you want to remove " & Selection.Cells.Hyperlinks.Count & " hyperlinks ?", _
                vbQuestion + vbYesNo)
                
If answer = vbNo Then
   Exit Sub
End If

For lhypercount = Selection.Cells.Hyperlinks.Count To 1 Step -1
   Set objhyperlink = Selection.Cells.Hyperlinks(lhypercount)
   objhyperlink.Delete
Next lhypercount
   
   Call MsgBox("done")
End Sub

Private Sub Worksheet_FollowHyperlink(ByValTarget As Hyperlink) 
   Call Hyperlink_Activate(Target)
End Sub

Public Sub Hyperlink_Activate(ByVal objHyperlink As Hyperlink) 
Dim sScreenTip As String
   sScreenTip = objHyperlink.ScreenTip

   Select Case sScreenTip
      Case "MacroName"
'do something
'maybe even update the ScreenTip
      objHyperlink.ScreenTip = "Blah blah"

   End Select

End Sub

This can be used to invoke an action or a macro
To create a hyperlink that just takes you to another part of the workbook
right click the cell, choose hyperlink
Select "place in the document" button on the left
In the "type the cell reference" add the cell you want to contain the link
This ensures that the selection doesn't change when the user presses the link.
This links the cell to itself


The following events are raised:
Application.SheetFollowHyperlink
Workbook.SheetFollowHyperlink
Worksheet.FollowHyperlink


© 2026 Better Solutions Limited. All Rights Reserved. © 2026 Better Solutions Limited TopPrev