week 10

advertisement
Excel VBA – Part 10
VBA for Microsoft Excel – Part 10
Contents
The Add method is the usual way to create a name e.g.
1
Names.Add Name:="ExamMarks", RefersTo:="=Exams!$A$2:$D$10"
2
3
4
5
6
7
8
Named Ranges ............................................................................................... 1
1.1
Creating a named range .......................................................................... 1
1.2
Selecting a named range .......................................................................... 1
1.3
Creating Names from a Selection ............................................................ 2
1.4
Redefining a named range after adding data to it ................................... 2
Comparing values in two ranges ................................................................. 3
Application object .......................................................................................... 3
Protecting VBA projects ................................................................................ 4
Protecting Worksheets................................................................................... 4
5.1
Protecting the active sheet ....................................................................... 4
5.2
Protecting all sheets using for each ......................................................... 4
Error handling ................................................................................................ 4
Events .............................................................................................................. 6
7.1
The Worksheet_Change Event ................................................................ 6
Page Setup and Printing ................................................................................ 6
8.1
BeforePrint event..................................................................................... 7
The RefersTo property must be specified in A1 style notation, including
dollar signs where appropriate.
However, the macro recorder generates this code to create a Name
Sub Macro2()
ActiveWorkbook.Names.Add Name:="ExamMarks", _
RefersToR1C1:="=Exams!R2C1:R10C4"
End Sub
The RefersToR1C1 property is used to reference ranges in a different
notation, e.g. R1C8 refers to the first row eighth column of the worksheet,
ie. cell H1. Therefore it is still an absolute reference.
1.2
Selecting a named range
You can select a range with a statement like
Range("ExamMarks").Select (assuming the range is on the active
sheet.) However, the macro recorder records the line above as
1 Named Ranges
Programs can be made easier by using Named Ranges which corresponds to
the Names collection in VBA. The following examples are to be used with
the Exams worksheet in xlvba10.xls
Application.GoTo Reference:= "ExamMarks"
1.1
Application.Goto Reference:="R1C8"
which is equivalent to Range("H1").Select
Creating a named range
There is a simple way if your code preselects a region and then:
Selection.Name="Nametext"
where Nametext is your choice of name.
This alternative way is in fact essential if you want to select a named
range that is not on the active sheet.
GoTo
can also be usde a statement like:
One advantage of using GoTo is that it has the capacity to ‘remember’ the
address of the range you start from, therefore there is the potential to make
Page 1 of 7
Excel VBA – Part 10
a macro return to a given location on a worksheet. The command for this is
Application.GoTo
The following macro assumes A2:D10 on the worksheet Exams is a range
named ExamMarks. What it does is loop through the totals and copies the
higher ones and pastes to column H. The totals are the result of a formula
and therefore need Paste Special
Sub ExtractHighScores()
Dim i As Integer
i = 1
Worksheets("Exams").Activate
Range("ExamMarks").Columns(4).Select
Do
If ActiveCell.Value >= 100 Then
ActiveCell.Copy
Application.Goto Reference:="R" & i & "C8"
Selection.PasteSpecial Paste:=xlPasteValues
Application.CutCopyMode = False
i = i + 1
Application.Goto
End If
ActiveCell.Offset(1, 0).Select
Loop Until ActiveCell = ""
End Sub
If you want to copy and paste both the name and mark to the new
location there is only one alteration to make. The line ActiveCell.Copy
becomes
Union(ActiveCell, ActiveCell.Offset(0, -3)).Copy
It’s useful to step through this macro and watch it work.
1.3
Creating Names from a Selection
There is a very efficient way to create names from existing worksheet
data. Given a selectiont as illustrated below . . .
. . . select the Formulas ribbon, click Create from Selection
and if you select only the Top Row checkbox, Excel will create names
from each of the selected column headings i.e. Date, Open, High and so on.
The code for this is would be:
Selection.CreateNames Top:=True, Left:=False, _
Bottom:=False, Right:=False
1.4
Redefining a named range after adding data to it
There is no method that ‘redefines’ the address of an existing named
range, for example, once you have added or deleted data from it. What
you do is to use Names.Add to add the range again with the updated
dimensions. Rather than struggling to concatenate the update literal
range reference an easier way is to make your code select the range, then
use a reference to Selection for the RefersTo argument. For example,
Names.Add Name:="ExamMarks", RefersTo:= Selection
which could be written more tersely
Names.Add "ExamMarks", Selection
If the range is in a single column you can use Selection.CreateNames as
described in the previous section, i.e create the range again with the
updated dimensions.
Page 2 of 7
Excel VBA – Part 10
Can you determine whether the active cell is in a particular range?
Yes, with some difficulty. Assuming you want to test if the active cell is in a
named range called ExamMarks then the following expression gives True
Union(ActiveCell,Range("ExamMarks")).Address =
Range("ExamMarks").Address
or to test if the active cell is in the used range:
Union(ActiveCell,ActiveSheet.usedrange).Address =
ActiveSheet.usedrange.Address
2 Comparing values in two ranges
It is possible to process two (or more) ranges in parallel by using the same
loop. Using the ftse worksheet, there are two named ranges Close13 and
Close12. The following program simply colours the font red if the closing
price for each month in 2013 is lower than for the corresponding month in
2012, and green if it is higher.
The code takes advantage of the fact that the two ranges are of the same size
and can use the count property of one or the other as the upper bound of the
For loop:
For i = 1 To close13.count
but you might have to code a test to see which range is larger.
Sub CompareRanges()
Dim i As Integer
Dim close13 As Range, close12 As Range
Set close13 = Range("Close2013")
Set close12 = Range("Close2012")
For i = 1 To close13.Count
If close13(i) < close12(i) Then
close13(i).Font.Color = vbRed
Else
close13(i).Font.Color = vbGreen
End If
Next i
End Sub
Note also the use of range variables using Set, which to make the code more
compact.
3
Application object
Application has useful properties/methods that can improve various aspects
of a macro. The first two are Boolean, i.e. set them to True or False.
Application.ScreenUpdating
Application.ScreenUpdating suppresses the visual display when a macro is
running. Note that using Step Into is impossible if ScreenUpdating is set to False.
Application.DisplayAlerts
Application.DisplayAlerts can be set to False while a macro is running to stop
Excel messages interfering with the smooth running of the macro. It is essential
to set it back to True before the End Sub, otherwise this setting will persist.
Application.InputBox
Not to be confused with the VBA Input box. Application.InputBox only accepts
data which conforms to a specific data type or there is an error. Type 8 is a
range, and the user must select a range on the worksheet.
Sub InputBoxForRange()
Dim rng1 As Range
On Error GoTo ExitPoint
Set rng1 = Application.InputBox _
(Prompt:="Select a Range", Type:=8)
MsgBox "You chose " & rng1.Address
Exit Sub
ExitPoint:
MsgBox "Object Required"
End Sub
Page 3 of 7
Excel VBA – Part 10
4
Protecting VBA projects
You can protect a VBA project to prevent unauthorised access to your code.
1.
2.
Open the Visual Basic Editor
Right-click the Project (corresponding to the filename) to be protected …
5
Protecting Worksheets
5.1 Protecting the active sheet
The Protect Sheet button is on the Review ribbon.
A line of code to protect the current sheet might look
like this.
3.
4.
and choose VBAProject Properties
Choose the Protection tab
ActiveSheet.Protect "abcd" True, True, True
Protect takes various arguments, including Password, followed by what
aspects of the worksheet are being protected – the values are True or False.
In the example the password is ‘abcd’ (case sensitive)
The corrsesponding line to UnProtect it is
ActiveSheet.UnProtect "abcd" True, True, True
5.2 Protecting all sheets using for each
A macro can protect all the sheets in the workbook with a For Each loop.
5.
Make sure that Lock Project for viewing is checked and type in a
password (twice), then choose OK
The code associated with this project can still be seen after you have done this.
To verify the password protection, close the file, then re-open it.
1.
2.
in VBE try to view the password-protected project
you must type the password into the box
Sub ProtectSheets()
Dim wk As Worksheet
For Each wk in Worksheets
wk.Protect “abcd”
Next wk
End Sub
6 Error handling
An error that arises during the running of a macro is known as a run-time
error. If you don't use an On Error statement, any run-time error that
occurs is fatal; that is, an error message is displayed and execution stops.
Page 4 of 7
Excel VBA – Part 10
The following discussion deliberately contrives an error. The code selects
a cell five rows above the current cell and colours it yellow – if there
aren’t five rows above the current cell when the macro is run a run-time
error occurs.
Sub Macro1()
ActiveCell.Offset(-5, 0).Select
ActiveCell.Interior.Color = vbYellow
End Sub
It is important to try to anticipate user errors. The usual way is to use On
Error GoTo to go to a designated line in the code (known as a label)
which is followed by some error handling code.
Sub Macro1()
On Error GoTo myErrorHandler
ActiveCell.Offset(-5, 0).Select
ActiveCell.Interior.Color = vbYellow
myErrorHandler:
Exit Sub
this line means ‘if an error
occurs go to the line
specified by the provided
label’ – here
myErrorHandler is the
label
a label is a word followed
by a colon
End Sub
At its most basic the error handling code could merely exit the sub (not
strictly necessary here as End Sub follows soon after). Of course this
would leave the user unaware that an error took place so you could add a
message box; it’s intuitive to think you do this just before the Exit Sub
statement
myErrorHandler:
MsgBox "You must start below Row 5"
Exit Sub
End Sub
but this would cause the message box to appear each time the macro
runs, even if the macro is successful. The trick is to put the Exit Sub
statement before the error handler and if the macro completes its task
successfully it terminates with the Exit Sub statement.
Sub Macro1a()
On Error GoTo myErrorHandler
ActiveCell.Offset(-5, 0).Select
ActiveCell.Interior.Color = vbYellow
Exit Sub
myErrorHandler:
MsgBox "You must start below Row 5"
End Sub
If you want a message box to return the ‘official’ error number and
description, use the Err object as follows:
MsgBox Err.Number & " " & Err.Description
In case you are interested the above macro could be improved as
follows:
If ActiveCell.Row > 5 Then
ActiveCell.Offset(-5, 0).Select
As well as a MsgBox, error handling code can be used to restore
Application defaults if they have been changed, for example it would be
important to include Application.DisplayAlerts = True if your code had
switched off Excel’s intereactive capabilities.
Resume
The keyword Resume is commonly used in error handling code. Resume
‘clears’ the error and makes it possible for the code to continue. You
may want a macro to continue regardless in spite of an error. The
statement:
On Error Resume Next
means ‘clear the error and continue with the next line of the macro’. For
Page 5 of 7
Excel VBA – Part 10
example you may want to continue calculating down a column even if
one calculation fails because of, say, a division by zero error.
Page orientation, settings for margins etc. are properties of the PageSetup
object, e.g.,
On Error Resume clears
Sub PreviewExams()
' page setup example
Worksheets("Exams").Select
With ActiveSheet.PageSetup
.Orientation = xlLandscape
.LeftFooter = ThisWorkbook.FullName
.RightFooter = Application.UserName
.LeftMargin = Application.InchesToPoints(2.5)
.HeaderMargin = Application.InchesToPoints(0.3)
.CenterHorizontally = True
.Zoom = 150
End With
ActiveSheet.PrintPreview
End Sub
the error and resumes with the current statement,
i.e. the statement that caused the error. It’s rare that this is of any use,
normally this would create an endless situation of clearing the error only
to recreate it. NB: you can only use Resume in the context of an error; it
is an error in itself to use Resume outside of an error sitation.
7
Events
7.1 The Worksheet_Change Event
This event occurs when the value of a cell on the worksheet changes. You
could exploit it if you have volatile data. The code example simulates a
worksheet with external links like prices or exchange rates. A change to any
value triggers a colour change for every cell on the worksheet.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rng As Range
For Each rng In Range("prices")
If IsNumeric(rng) And Not IsEmpty(rng) Then
If rng >= 16 Then
rng.Font.Color = vbGreen
ElseIf rng < 15 Then
rng.Font.Color = vbRed
Else
rng.Font.Color = vbBlack
End If
End If
Next rng
End Sub
8
Page Setup and Printing
Every worksheet has its own PageSetup, therefore it follows that the Worksheet
object contains the PageSetup object
Print Areas
By default the whole worksheet is printed. To designate a worksheet area to be
printed use the PrintArea property of PageSetup, e.g.,
ActiveSheet.PageSetup.PrintArea = "$A$1:$C$10"
For more flexibility you can use the Address property of Selection
ActiveSheet.PageSetup.PrintArea = Selection.Address
You can use the comma as the Union operator
ActiveSheet.PageSetup.PrintArea = "$A$1:$C$10,$C$2:$C$12"
.
To clear a Print Area the code is
ActiveSheet.PageSetup.PrintArea = ""
Page Breaks
To add manual Page Breaks use HPageBreaks or VPageBreaks. For example to
add page breaks before the active cell:
ActiveSheet.HPageBreaks.Add Before:=ActiveCell
ActiveSheet.VPageBreaks.Add Before:=ActiveCell
Page 6 of 7
Excel VBA – Part 10
To clear Page Breaks use
ActiveSheet.ResetAllPageBreaks
There are only objects for manual Page Breaks. To control automatic Page
Breaks the only way is to change the page margins
8.1 BeforePrint event
You can use the BeforePrint event of the workbook make changes to PageSetup
every time any worksheet is printed.
Private Sub Workbook_BeforePrint(Cancel As Boolean)
Dim wk As Worksheet
Dim CompanyName As String
CompanyName = "City University"
For Each wk In Worksheets
With wk.PageSetup
.LeftFooter = CompanyName
.RightFooter = ThisWorkbook.FullName
End With
Next wk
End Sub
Page 7 of 7
Download