Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 36

Adding the Dynamic Named Range

When we import the data we are importing to a worksheet range on the Import sheet that is being referenced by a
dynamic named range to form the rowsource in our Userform.
That being the case we are going to need to create a dynamic named range for our import data.
Open the Name Manager and add this New named range.
Named range called: DataAccess
=OFFSET(Import!$A$1,1,,COUNTA(Import!$A$2:$A$10000),7)
 

Enabling a ADO
Hit ALT +F11 to open the VBA editor in Microsoft Excel and then also you can repeat this process in your Microsoft
Access program as well.
Click on Tools and then References, scroll down until you find Microsoft ActiveX Data Objects.
Click on the latest available library as shown in the illustration below.
 

 
 

Creating our Microsoft Access database


Before we start we need to have a little database that we can send and retrieve data to and from.
Create a simple database as shown in the video above. (refer to previous tutorials is if you are having difficulty with
this)

1. Name the database PhoneBook


2. Add a table Named PhoneList
3. Add data to the table

Setting the file Path


If you are using a file from previous tutorials you will already have this part added to your Excel file. Do not
duplicated this code.
Because we will be referencing a file path to the Access database and that file path could change because the
database could be moved to another folder or to a network drive we want to make that part a flexible part of our code.
To do this we will put the file path into a cell reference and then reference that cell location to gain the path at any
time or location.
Hit ALT +F11 to open the VBA editor in Microsoft Excel and then in the module called Excel_Access in the template
provided paste the code below.
Sub GetPath07()
Dim FName As Variant
FName = Application.GetOpenFilename(filefilter:="Access Files,*.acc*")
Sheet1.Range("I3").Value = FName
End Sub
Assign this macro to the shape called Get the File Path on the Export worksheet by right clicking the shape and
then choosing Assign Macro and selecting the macro and then clicking OK.
 

Creating the Userform


Hit ALT +F11 to open the VBA editor.
Here is an illustration of the Userform that we will be creating. If you have not already done so then please watch the
video above closely before creating this Userform.

Make sure that you name the text boxes and command buttons are exactly as shown in the video above. Failures to
do this will result in our code throwing an error.

 13 Labels
 8 Textboxes  (Arec1 to Arec7) (txtSearch)
 3 Command Buttons  (cmdAdd,cmdImport,cmdClose)
 1 Checkbox  (do not rename)
 1 Listbox  (lstDataAccess)

 
 

Show the Userform (The module)


Add the code below into your module in the VBA editor. Then right click on the shape on the Exportworksheet
named Userform and Assign Macro and select the macro below.
Now when you click on that shape the Userform that you have created should appear in the later above your
worksheet.
Sub Showme()
frmExcelAccess.Show
End Sub
 
 

Userform Initialize (Userform)


This code will run when your Userform initialises. Make sure that you put this code into the Userform itself
and not into a module.
Private Sub UserForm_Initialize()
Me.Arec1 = Sheet1.Range("J3").Value
End Sub
 
 

Userform Close
This is the code for the close button on our Userform.
Private Sub cmdClose_Click()
Unload Me
End Sub
 
 

Exporting the Data


Here is our code for adding the values from the controls on a Userform to access database. You will note that I have
put in extensive comments in here.
Take the time to look carefully through this code to try to understand what it is doing so that you may be in a
position to adapt this to your own database.
Private Sub cmdAdd_Click()
Dim cnn As ADODB.Connection 'dim the ADO collection class
Dim rst As ADODB.Recordset 'dim the ADO recordset class
Dim dbPath
Dim x As Long, i As Long
'Erro handler
On Error GoTo errHandler:
dbPath = ActiveSheet.Range("I3").Value
Set cnn = New ADODB.Connection ' Initialise the collection class variable
'Connection class is equipped with a —method— named Open
'—-4 aguments—- ConnectionString, UserID, Password, Options
'ConnectionString formula—-Key1=Value1;Key2=Value2;Key_n=Value_n;
cnn.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & dbPath
'two primary providers used in ADO SQLOLEDB —-Microsoft.JET.OLEDB.4.0 —-Microsoft.ACE.OLEDB.12.0
'Object Linking and Embedding, Database
'ADO library is equipped with a class named Recordset
Set rst = New ADODB.Recordset 'assign memory to the recordset
'ConnectionString Open '—-5 aguments—-
'Source, ActiveConnection, CursorType, LockType, Options
rst.Open Source:="PhoneList", ActiveConnection:=cnn, _
CursorType:=adOpenDynamic, LockType:=adLockOptimistic, _
Options:=adCmdTable
'you now have the recordset object
'alternative code
'With rst
'.AddNew
'.Fields("Id").Value = Arec1
'.Fields("Surname").Value = Arec2
'.Fields("FirstName").Value = Arec3
'.Fields("Address").Value = Arec4
'.Fields("Phone").Value = Arec5
' .Fields("Mobile").Value = Arec6
'.Fields("Email").Value = Arec7
'.Update
'End With
'send the data
rst.AddNew
For i = 1 To 7
rst(Cells(1, i).Value) = Me.Controls("Arec" & i).Value
Next i
rst.Update
'update for the next ID
Sheet1.Range("J3").Value = Arec1.Value + 1
'clear the userform values
For x = 1 To 7
Me.Controls("Arec" & x).Value = ""
Next
'add the next user ID
Me.Arec1 = Sheet1.Range("J3").Value
' Close the connection
rst.Close
cnn.Close
Set rst = Nothing
Set cnn = Nothing
'commuinicate with the user
MsgBox " The data has been successfully sent to the access database"
On Error GoTo 0
Exit Sub
errHandler:
Set rst = Nothing
Set cnn = Nothing
MsgBox "Error " & Err.Number & " (" & Err.Description & ") in procedure cmdAdd"
End Sub
 
 

Importing the Data from Access


Here is the code for importing our data into the listbox in our Userform. Remember earlier I mentioned that first we
are going to import the range of data to our worksheet and then reference that range in the row source for the listbox
in the Userform.
Take the time to look carefully through this code to try to understand what it is doing so that you may be in a
position to adapt this to your own database.
Private Sub cmdImport_Click()
'Declaring the necessary variables.
Dim cnn As ADODB.Connection 'dim the ADO collection class
Dim rs As ADODB.Recordset 'dim the ADO recordset class
Dim dbPath As String
Dim SQL As String
Dim i As Integer
Dim var as range
'add error handling
On Error GoTo errHandler:
'Disable screen flickering.
Application.ScreenUpdating = False
'clear the values from the worksheet
Sheet2.Range("A2:G10000").ClearContents
'get the path to the database
dbPath = Sheet1.Range("I3").Value
'set the search variable
var = Me.txtSearch
Set cnn = New ADODB.Connection ' Initialise the collection class variable
'Connection class is equipped with a —method— named Open
'—-4 aguments—- ConnectionString, UserID, Password, Options
'ConnectionString formula—-Key1=Value1;Key2=Value2;Key_n=Value_n;
cnn.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & dbPath
'Create the SQL statement to retrieve the data from table.
If CheckBox1 = True Then
SQL = "SELECT * FROM PhoneList WHERE SURNAME = '" & var & "'"
Else
SQL = "SELECT * FROM PhoneList WHERE SURNAME LIKE '" & var & "%" & "'"
End If
'Create the ADODB recordset object.
Set rs = New ADODB.Recordset 'assign memory to the recordset
'ConnectionString Open '—-5 aguments—-
'Source, ActiveConnection, CursorType, LockType, Options
rs.Open SQL, cnn
'Check if the recordset is empty.
If rs.EOF And rs.BOF Then
'Close the recordet and the connection.
rs.Close
cnn.Close
'clear memory
Set rs = Nothing
Set cnn = Nothing
'Enable the screen.
Application.ScreenUpdating = True
'In case of an empty recordset display an error.
MsgBox "There are no records in the recordset!", vbCritical, "No Records"
Me.lstDataAccess.RowSource = ""
Exit Sub
End If
'Write the reocrdset values in the sheet.
Sheet2.Range("A2").CopyFromRecordset rs
'Close the recordset and the connection.
rs.Close
cnn.Close
'clear memory
Set rs = Nothing
Set cnn = Nothing
'Enable the screen.
Application.ScreenUpdating = True
Me.lstDataAccess.RowSource = "DataAccess"
'Inform the user that the macro was executed successfully.
MsgBox "Congratulation the data has been successfully Imported", vbInformation, "Import successful"
'error handler
On Error GoTo 0
Exit Sub
errHandler:
'clear memory
Set rs = Nothing
Set cnn = Nothing
MsgBox "Error " & Err.Number & " (" & Err.Description & ") in procedure Import_Data"
End Sub
 
 
Append and delete

Enabling a ADO
See previous tutorial
 

Creating our Microsoft Access database


Check previous tutorial
 

Setting the file Path


Check the previous tutorial.
 
 

Adding 2 new Command Buttons to the Userform


 
Hit ALT +F11 to open the VBA editor.
Double-click on the userform to activate it in the VBA editor and add two command buttons.
1. Name the first one cmdAppend
2. Name the second one cmdDelete
 

Listbox DoubleClick Event


Here is the double click event for sending the values from the listbox to the textbox controls.
Private Sub lstDataAccess_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
'dim the variables
Dim i As Integer
'find the selected list item
i = Me.lstDataAccess.ListIndex
Me.lstDataAccess.Selected(i) = True
'add the values to the text boxes
Me.Arec1.Value = Me.lstDataAccess.Column(0, i)
Me.Arec2.Value = Me.lstDataAccess.Column(1, i)
Me.Arec3.Value = Me.lstDataAccess.Column(2, i)
Me.Arec4.Value = Me.lstDataAccess.Column(3, i)
Me.Arec5.Value = Me.lstDataAccess.Column(4, i)
Me.Arec6.Value = Me.lstDataAccess.Column(5, i)
Me.Arec7.Value = Me.lstDataAccess.Column(6, i)
End Sub

Modifying the Import Procedure


 
We need to make a modification to the import code that we have previously used in the userform.
The userform Import command button click event activates this procedure. (when you click the button).
You will find this code here.   Userform to Export and Import
Private Sub cmdImport_Click()
Change the name of this procedure to
Sub ImportUserForm()
Then double-click on the import button in the userform the VBA editor and add the code below.
What is the reason for this change.
The reason is that we need to call the import procedure after we have Appended and Deleted record sets in our
access database.
We will now be able to do this by adding "ImportUserForm" after appending an deleting our data. You will also notice
that we have removed the message box from the import procedure and added it to our private sub.
Have you now have two macros instead of one and this is how they should look.
Import button click event
Private Sub cmdImport_Click()
ImportUserForm
'Inform the user that the macro was executed successfully.
MsgBox "Congratulation the data has been successfully Imported", vbInformation, "Import successful"
End Sub
The import macro that is called.
Sub ImportUserForm()
'Declaring the necessary variables.
Dim cnn As ADODB.Connection 'dim the ADO collection class
Dim rs As ADODB.Recordset 'dim the ADO recordset class
Dim dbPath As String
Dim SQL As String
Etc…………………………………………Etc…………………………………………
 

Adding the Code to Append


 
Here is the code to append the MS Access record set. If you are not familiar with the ADODB database connection or
OLEDB Microsoft provider then please refer to my previous tutorials.
Note: Unlike our other SQL statements this time we will be referencing the ID field in our MS Access dataset.
Why is this?
It is because we want to be very specific with the record sets that we append and delete. The ID field isunique and
so if we reference it we should not make a mistake.
If we were to use the last name or other fields it is possible that we could find duplicates and append or delete the
wrong information.
You will notice I have added extensive comments to this code as with all of the other code in this series. Take the
time to read them they will help you to understand what each section of code is doing.
Private Sub cmdAppend_Click()
'Declaring the necessary variables.
Dim cnn As ADODB.Connection 'dim the ADO collection class
Dim rs As ADODB.Recordset 'dim the ADO recordset class
Dim dbPath As String
Dim i As Integer
Dim x As Integer
'add error handling
On Error GoTo errHandler:
If Me.Arec1.Value = "" Then
MsgBox "You must enter a valid ID number.", _
vbOKOnly Or vbInformation, "Insufficent data"
Exit Sub
End If
'get the path to the database
dbPath = Sheet1.Range("I3").Value
Set cnn = New ADODB.Connection ' Initialise the collection class variable
'Connection class is equipped with a —method— named Open
'—-4 aguments—- ConnectionString, UserID, Password, Options
'ConnectionString formula—-Key1=Value1;Key2=Value2;Key_n=Value_n;
cnn.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & dbPath
Set rs = New ADODB.Recordset 'assign memory to the recordset
'Create the SQL statement to retrieve the data from table.
rs.Open "SELECT * FROM PhoneList " & _
"WHERE ID = " & CLng(Me.Arec1), ActiveConnection:=cnn, _
CursorType:=adOpenDynamic, LockType:=adLockOptimistic, _
Options:=adCmdText
If rs.EOF And rs.BOF Then
'Close the recordet and the connection.
rs.Close
cnn.Close
'clear memory
Set rs = Nothing
Set cnn = Nothing
'Enable the screen.
Application.ScreenUpdating = True
'In case of an empty recordset display an error.
MsgBox "There are no records in the recordset!", vbCritical, "No Records"
Exit Sub
End If
With rs
For i = 1 To 7
rs(Cells(1, i).Value) = Me.Controls("Arec" & i).Value
Next i
rs.Update
End With
'clear the userform values
For x = 1 To 7
Me.Controls("Arec" & x).Value = ""
Next
'Close the recordset and the connection.
rs.Close
cnn.Close
'clear memory
Set rs = Nothing
Set cnn = Nothing
'refresh the listbox
ImportUserForm
'Enable the screen.
Application.ScreenUpdating = True
Me.lstDataAccess.RowSource = "DataAccess"
'Inform the user that the macro was executed successfully.
MsgBox "Congratulation the data has been appended", vbInformation, "Append successful"
'error handler
On Error GoTo 0
Exit Sub
errHandler:
'clear memory
Set rs = Nothing
Set cnn = Nothing
MsgBox "Error " & Err.Number & " (" & Err.Description & ") in procedure Import_Data"
End Sub
 

Code to Delete
 
You will notice again in this procedure that we are referencing our ID field. This is for the reason given above.
 
Private Sub cmdDelete_Click()
'Declaring the necessary variables.
Dim cnn As ADODB.Connection 'dim the ADO collection class
Dim rs As ADODB.Recordset 'dim the ADO recordset class
Dim dbPath As String
Dim i As Integer
Dim x As Integer
'add error handling
On Error GoTo errHandler:
If Me.Arec1.Value = "" Then
MsgBox "You must enter a valid ID number.", _
vbOKOnly Or vbInformation, "Insufficent data"
Exit Sub
End If
'get the path to the database
dbPath = Sheet1.Range("I3").Value
Set cnn = New ADODB.Connection ' Initialise the collection class variable
'Connection class is equipped with a —method— named Open
'—-4 aguments—- ConnectionString, UserID, Password, Options
'ConnectionString formula—-Key1=Value1;Key2=Value2;Key_n=Value_n;
cnn.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & dbPath
Set rs = New ADODB.Recordset 'assign memory to the recordset
'Create the SQL statement to retrieve the data from table.
rs.Open "SELECT * FROM PhoneList " & _
"WHERE ID = " & CLng(Me.Arec1), ActiveConnection:=cnn, _
CursorType:=adOpenDynamic, LockType:=adLockOptimistic, _
Options:=adCmdText
If rs.EOF And rs.BOF Then
'Close the recordet and the connection.
rs.Close
cnn.Close
'clear memory
Set rs = Nothing
Set cnn = Nothing
'Enable the screen.
Application.ScreenUpdating = True
'In case of an empty recordset display an error.
MsgBox "There are no records in the recordset!", vbCritical, "No Records"
Exit Sub
End If
'delete the record set
rs.Delete
'clear the userform values
For x = 1 To 7
Me.Controls("Arec" & x).Value = ""
Next
'Close the recordset and the connection.
rs.Close
cnn.Close
'clear memory
Set rs = Nothing
Set cnn = Nothing
'Enable the screen.
Application.ScreenUpdating = True
'refresh the listbox
ImportUserForm
'set the rowsourse
Me.lstDataAccess.RowSource = "DataAccess"
'Inform the user that the macro was executed successfully.
MsgBox "Congratulation the data has been deleted", vbInformation, "Deletion successful"
'error handler
On Error GoTo 0
Exit Sub
errHandler:
'clear memory
Set rs = Nothing
Set cnn = Nothing
MsgBox "Error " & Err.Number & " (" & Err.Description & ") in procedure Import_Data"
End Sub
 

List of Common Excel Operations


Here is the list of commonly used excel operation. In this tutorial, I’ve performed all these
operations in SQL:

1. View Data
2. Sort Data
3. Filter Data
4. Delete Records
5. Add Records
6. Update Data in Existing Record
7. Show Unique Values
8. Write an expression to generate new column
9. LookUp data from another table
10. Pivot Table
To perform operations listed above, I’ll use the data listed below (Employee)\:

1. View Data
In excel, we can view all the records directly. But, SQL requires a command to process this
request. This can be done by using SELECT command.

Syntax:

SELECT column_1,column_2,…column_n | *  FROM table_name;

Exercise:

A. View all data of Employee table


Select * from Employee;

B. View only ECODE and Gender data of Employee table

Select ECODE, Gender from Employee

2. Sort Data
Organizing information becomes important when you have more data. It helps to generate
quick inferences. You can quickly organize an excel worksheet by sorting your data in
ascending or descending order.

Syntax:

SELECT column_1,column_2,…column_n | *  FROM table_name order by column_1


[desc], column_2 [desc];
Exercise:

A. Arrange records of Employee table in Descending order of Total_Payout.

Select * from Employee order by Total_Payout desc;

B. Arrange records of Employee table by City (ascending) and


Total_Payout(descending).

Select * from Employee order by City, Total_Payout desc;

 
3. Filter Data
In addition to sorting, we often apply filter to analyze data in a better way. When data is
filtered, only rows that meet the filter criteria is displayed while other rows get hidden. Also,
we can apply multiple criterion to filter data.

Syntax:

SELECT column_1,column_2,…column_n | *  FROM table_name where


column_1 operator value;

Below are the common list of operators, we can use to form a condition.

Operator Description

= Equal

Not equal. Note: In some versions of SQL this operator may be written as !


<>
=

> Greater than

< Less than

>= Greater than or equal

<= Less than or equal

BETWEEN Between an inclusive range

LIKE Search for a pattern

IN To specify multiple possible values for a column

Exercise:

A. Filter observations associated with city “Delhi”


Select * from Employee where City="Delhi";

B. Filter observations of Department “Admin” and Total_Payout >= 500

Select * from Employee where Department="Admin" and Total_Payout >=500;

4. Delete Records
Deleting records or columns is a commonly used operation in Excel. In excel, we simply
press ‘Delete’ key on keyboard to delete a record. Similarly, SQL has command DELETE to
remove records from a table.

Syntax:

DELETE FROM table_name WHERE some_column=some_value;

Exercise:

A. Delete observations which have Total_Payout >=600

Delete * from Employee where Total_Payout >=600;

It removes two record only since these two observations satisfy the condition stated above.
But be careful! if we do not provide any condition, it will remove all records from a table.

B. Delete observations which have Total_Payout >=600 and Department =”Admin”


Delete * from Employee where Total_Payout >=600 and Department ="Admin";

Above command will remove only one record which satisfies the condition.

5. Add records
We have seen methods to remove records, we can also add records to SQL table as we do
in excel. INSERT command helps to perform this operation.

Syntax:

INSERT INTO table_name VALUES (value1, value2, value3,…); -> Insert values to all


columns

OR,

INSERT INTO table_name (column1,column2,column3,…) VALUES
(value1,value2,value3,…); -> Insert values to selected columns

Exercise:

A. Add below records to the table ‘Employee’

Insert into employee values('A002','05-Nov-

12',0.8,'Female','Admin',12.05,26,313.3,'Mumbai');

Select * from Employee where ECODE='A002';

B. Insert values to ECODE (A016) and Department (HR) only.


Insert into employee (ECODE, Department) values('A016','HR');

Select * from Employee where Department='HR';

6. Update Data in Existing Observations


Suppose, we want to update the name of “HR” department to “Manpower” for all
employees. For such cases, SQL has a command UPDATE which performs this function.

Syntax:

UPDATE table_name SET column1=value1,column2=value2,… WHERE


some_column=some_value;

Exercise: Rename Department “HR” to “Manpower”

Update Employee SET Department='Manpower' where Department='HR';


Select * from Employee;

7. Show unique values


We can show unique values of variable(s) by applying DISTINCT keyword prior to variable
name.

Syntax: 

SELECT DISTINCT column_name,column_name FROM table_name;

Exercise: Show unique values of City

Select distinct City from Employee;

8. Write an expression to generate new column


In excel, we can create a column, based on existing column using functions or operators.
This can be done in SQL using the commands below.
Exercise:

A. Create a new column Incentive which is 10% of Total_Payout

Select *, Total_Payout*01 as Incentive from Employee;

B. Create a new column City_Code which has first three characters of City.

Select *, Left(City,3) as City_Code from Employee where Department="Admin";

For more details on SQL functions, I would recommend you to refer this link.

9. LookUp data from another table


The most used function of excel by any BI professional / data analyst is VLOOKUP(). It
helps to map data from other table to parent table. In other words, we can say that it is the
‘excel’ way of joining 2 data sets through a common key.

In SQL, we have similar functionality known as JOIN.

SQL JOIN is used to combine rows from two or more tables, based on a common field
between them. It has multiple types:
 INNER JOIN: Return rows when there is a match in both tables
 LEFT JOIN: Return all rows from the left table and the matched rows from the right
table
 RIGHT JOIN: Return all rows from the right table and the matched rows from the left
table
 FULL JOIN: Return all rows when there is a match in ONE of the tables

Syntax: 

SELECT table1.column1, table2.column2..... FROM table1 INNER | LEFT| RIGHT| FULL JOIN

table2 ON table1.column = table2.column;

Exercise: Below is city category table “City_Cat”, now I want to map city category to

Employee table and show all records of Employee table. Here,


I want to show all records of table Employee. So, we will use left join.

SELECT Employee.*,City_Cat.City_Category FROM Employee LEFT JOIN City_Cat ON

Employee.City = City_Cat.City;

To know more about JOIN operations, I would recommend you to refer this link.

 
10. Pivot Table
Pivot Table is an advanced way of analyzing data in excel. Not only it is useful, but it allows
you to extract the hidden insights from data.

Moreover, it helps us to generate inference by summarizing data and allow


us to manipulate it in different ways. This operation can be done in SQL by using
aggregate functions and GROUP BY command.

Syntax:

SELECT column, aggregate_function(column) FROM table WHERE column operator


value GROUP BY column;

Exercise: 

A. Show sum of Total_Payout by Gender

SELECT Gender, Sum(Total_Payout) from Employee Group by Gender;

B. Show sum of Total_Payout and Count of Records by


Gender and City

SELECT Gender, City, Count(City), Sum(Total_Payout) from Employee Group by Gender,

City;
Add Progress Bar Macros
When your progress bar pops up, you don’t want the ugly title bar with the red X to show up,
right? I didn’t think so.

Hide Title Bar


To remove the title bar, I’m going to borrow a macro from my Remove Window Border
tutorial. If the person using the spreadsheet you’re creating is a Mac user, this macro won’t
work, but I’ll show you how to prevent it from crashing on them later.

1. Insert a Standard Module


1. Right-click the Project Explorer Pane
2. Hover over Insert
3. Click Module

2. Change the (Name) property of the Module to HideTitleBar


3. Paste the following macro into the new module you just created:

'PLACE IN STANDARD MODULE


Option Explicit
Option Private Module

Public Const GWL_STYLE = -16


Public Const WS_CAPTION = &HC00000
#If VBA7 Then
Public Declare PtrSafe Function GetWindowLong _
Lib "user32" Alias "GetWindowLongA" ( _
ByVal hWnd As Long, _
ByVal nIndex As Long) As Long
Public Declare PtrSafe Function SetWindowLong _
Lib "user32" Alias "SetWindowLongA" ( _
ByVal hWnd As Long, _
ByVal nIndex As Long, _
ByVal dwNewLong As Long) As Long
Public Declare PtrSafe Function DrawMenuBar _
Lib "user32" ( _
ByVal hWnd As Long) As Long
Public Declare PtrSafe Function FindWindowA _
Lib "user32" (ByVal lpClassName As String, _
ByVal lpWindowName As String) As Long
#Else
Public Declare Function GetWindowLong _
Lib "user32" Alias "GetWindowLongA" ( _
ByVal hWnd As Long, _
ByVal nIndex As Long) As Long
Public Declare Function SetWindowLong _
Lib "user32" Alias "SetWindowLongA" ( _
ByVal hWnd As Long, _
ByVal nIndex As Long, _
ByVal dwNewLong As Long) As Long
Public Declare Function DrawMenuBar _
Lib "user32" ( _
ByVal hWnd As Long) As Long
Public Declare Function FindWindowA _
Lib "user32" (ByVal lpClassName As String, _
ByVal lpWindowName As String) As Long
#End If
Sub HideTitleBar(frm As Object)
Dim lngWindow As Long
Dim lFrmHdl As Long
lFrmHdl = FindWindowA(vbNullString, frm.Caption)
lngWindow = GetWindowLong(lFrmHdl, GWL_STYLE)
lngWindow = lngWindow And (Not WS_CAPTION)
Call SetWindowLong(lFrmHdl, GWL_STYLE, lngWindow)
Call DrawMenuBar(lFrmHdl)
End Sub

Add Macro to UserForm


Once you do this, go back to your ufProgress form and follow these steps:

1. Right click anywhere on your ufProgress form and select View Code


2. Clear out any macros that may appear on the form
3. Paste the following macro:

'PLACE IN YOUR USERFORM CODE


Private Sub UserForm_Initialize()
#If IsMac = False Then
'hide the title bar if you're working on a windows machine.  Otherwise, just
display it as you normally would
Me.Height = Me.Height - 10
HideTitleBar.HideTitleBar Me
#End If
End Sub

The IsMac check in this routine is what prevents the macro from crashing for users running
Excel on a Mac. Instead of the sleek UserForm without a title bar, they’ll see the title bar. In
other words, their Progress Bars won’t be as pretty as you Windows users, but that’s okay,
right!? ;)

Display Progress Bar


Now that you’re done designing your progress bar and configuring the macros, it’s time to
figure out how to incorporate the progress bar into your existing macro.

This is where you may have to adapt the solution I provide into your own application. This
might require you to think outside the box a bit, but I’m confident you can do that!

The best way to show you how to include the progress bar in your macro is to give you a
demonstration and then walk you through the important pieces.

In this example, I loop through all the rows in my spreadsheet and update my progress bar
after each row. Here’s the sample macro (pay attention to the comment cards):

'PLACE IN A STANDARD MODULE


Sub LoopThroughRows()
Dim i As Long, lastrow As Long
Dim pctdone As Single
lastrow = Range("A" & Rows.Count).End(xlUp).Row

'(Step 1) Display your Progress Bar


ufProgress.LabelProgress.Width = 0
ufProgress.Show
For i = 1 To lastrow
'(Step 2) Periodically update progress bar
pctdone = i / lastrow
With ufProgress
.LabelCaption.Caption = "Processing Row " & i & " of " & lastrow
.LabelProgress.Width = pctdone * (.FrameProgress.Width)
End With
DoEvents
'--------------------------------------
'the rest of your macro goes below here
'
'
'--------------------------------------
'(Step 3) Close the progress bar when you're done
If i = lastrow Then Unload ufProgress
Next i
End Sub

This sample has 3 important steps. These 3 steps are common whether or not your macro
uses a For loop like the one above.

Step 1 - Display your Progress Bar

At some point in your macro, you want to make your progress bar appear on your
screen.Chances are, you want to do this right after your macro starts to run. To do that, you
want to make sure the width of your progress bar is set to 0 at the beggining and then show
your UserForm. All you have to do is add the following lines to your macro, like I did in the
example above:

ufProgress.LabelProgress.Width = 0
ufProgress.Show

Step 2 - Periodically Update Progress Bar

At some point, you want to update the length of your progress bar to indicate how far along
your macro is. That’s the point of a progress bar, right? In my example, I used a formula to
calculate what percentange of the way through the macro I was, based on which row I was
processing.Inside the loop, I included the following code:

pctdone = i / lastrow
With ufProgress
.LabelCaption.Caption = "Processing Row " & i & " of " & lastrow
.LabelProgress.Width = pctdone * (.FrameProgress.Width)
End With
DoEvents

Each time I get to a new row, I update the LabelCaption text and the width of
myLabelProgress label.

This is a great way to indicate progress if your macro consists of a loop where you know the
starting position and you know the ending position. Examples where a solution like the one
above will work are when you’re processing each line of data in a spreadsheet, or looping
through files in a folder.

Step 3 - Close the Progress Bar

When your macro is nearing completion, make sure you close your Progress Bar. In my
example, I closed the VBA Progress Bar UserForm when I got to the last row. I did that via
this line of code:

If i = lastrow Then Unload ufProgress

Create the Progress Bar and Userform


The first thing we need to do is create the userform and the progress bar. The userform
here will be quite simple, but other control and images could be used on yours.

The progress bar will be made from 3 controls. 1 Frame control and 2 label controls.

The frame will be the border of the progress bar. It is the light grey box you can see above.
Then 1 labels will be used for the bar, and another label for the text showing the percentage
complete above the bar.

1. Switch to the Visual Basic Editor by pressing Alt + F11, or clicking the Developer tab and
then Visual Basic.
2. Click Insert and then Userform.
3. Using the Properties window (if the Properties window is not shown, click View > Properties
Window) enter a name and caption for your userform.
In the image below you can see that my userform is named Progress, and I have used the
caption of Macro Progress.

Using the Toolbox, we will now insert the three controls that we need. These controls will
also be named using the Properties window for each. The caption has been deleted for
each control.

4. Click the Frame button on the Toolbox, and click and drag to draw it onto the userform. I
have named my frame as Border. I have also enter the Width as 200 (this will be used later).
5. Click on the Label button and draw that inside the frame. This label will be the bar, so I have
named it Bar. Click the BackColor property and select a colour you wish to use for the bar.
The palette tab offers a good selection.
6. Click the Label button again and draw this one above the progress bar. This one will show the
percentage complete, so I have named it Text. I have ensured that it is aligned with the frame
below it.
Update the Progress Bar with the Macros Progress
Now that we have the physical bar on the userform (it does not look like much yet) we need
it to automatically change width as the macro progresses.

Insert a new code module by clicking Insert > Module.


In this module I entered the following code, which I will explain.

This macro is a simple one that loops through every row of a sheet and multiplies the value
in column 10 (column J) by 1.1. We do not care about this, it is just some code to keep the
macro busy so we can see the progress bar working correctly.

Sub ProgressBar()

Dim i As Long
Dim TotalRows As Long
Dim CurrentProgress As Double
Dim ProgressPercentage As Double
Dim BarWidth As Long
i=2
TotalRows = Application.CountA(Range("A:A"))

Call InitProgressBar

Do While i <= TotalRows

Cells(i, 10).Value = Cells(i, 10).Value * 1.1

CurrentProgress = i / TotalRows
BarWidth = Progress.Border.Width * CurrentProgress
ProgressPercentage = Round(CurrentProgress * 100, 0)

Progress.Bar.Width = BarWidth
Progress.Text.Caption = ProgressPercentage & "% Complete"

DoEvents

i=i+1

Loop

Unload Progress

End Sub

Sub InitProgressBar()

With Progress
.Bar.Width = 0
.Text.Caption = "0% Complete"
.Show vbModeless

End With

End Sub

There are two subs here. One called ProgressBar and another called InitProgressBar.


The main sub is ProgressBar and this begins by declaring 3 variables. These
are CurrentProgress to be used to calculate the progress through the macro. BarWidth to
calculate the width that the progress bar should be at. And ProgressPercentage to store the
progress through the macro as a percentage (this is for the Text label above the progress
bar).

Dim CurrentProgress As Double


Dim ProgressPercentage As Double
Dim BarWidth As Long

Then before the loop starts we call the InitProgressBar macro.

Call InitProgressBar

This macro is used to initialise the progress bar on the userform. It sets the bar width to 0,
the text to 0% and then most importantly shows the userform.

With Progress

.Bar.Width = 0
.Text.Caption = "0% Complete"
.Show vbModeless

End With

The userform is set to be modeless. This means that the user can interact with other parts
of the spreadsheet whilst the userform is open. Modal forms do not allow this.
We then calculate the progress through the macro, and what width the progress bar should
be at. This is entered inside the loop so after each row of the loop, the user is aware of the
macro progress.

CurrentProgress = i / TotalRows
BarWidth = Progress.Border.Width * CurrentProgress
ProgressPercentage = Round(CurrentProgress * 100, 0)

Progress.Bar.Width = BarWidth
Progress.Text.Caption = ProgressPercentage & "% Complete"

The CurrentProgress is calculated by dividing the current row number (i variable) by the total
number of rows. There are 12931 rows on this sheet. If you are at row 9523, then you do
9523/12931 which results in 0.736447 through the macro.
Once we know this we can find out what width the progress bar should be by multiplying the
width of the border by this value. I set the width of the frame control named Border to 200,
so this would be 200 * 0.736447. The answer of 147 is assigned to the BarWidth variable.
We then calculate the progress as a percentage by multiplying the CurrentProgress value
by 100. The ROUND function is used to round this figure to 0 decimals. This results is
assigned to the ProgressPercentage variable to be used for the Text label.
The width of the progress bar and caption for the text label are then set.

The final bit of code is then the DoEvents statement. This ensures that events can still occur
whilst the macro runs.

DoEvents

Option Explicit

Sub InsertHeaderFooter()

Dim wsAs Worksheet


Application.ScreenUpdating = False
Each wsInThisWorkbook.Worksheets
                   With ws.PageSetup
                                       .LeftHeader = “Company Name:”
                                       .CenterHeader = “Page &P of &N”
                                       .RightHeader = “Printed &D &T”
                                       .LeftFooter = “Path : “ &ActiveWorkbook.Path
.CenterFooter = “Workbook Name: & F”
                                      .RightFooter = “Sheet: &A”
                  End With
Next ws
Set ws = Nothing
Application.ScreenUpdating = True
End Sub

Format
code Description

&L Left aligns the characters that follow.

&C Centers the characters that follow.

&R Right aligns the characters that follow.

&E Turns double-underline printing on or off.

&X Turns superscript printing on or off.

&Y Turns subscript printing on or off.

&B Turns bold printing on or off.

&I Turns italic printing on or off.

&U Turns underline printing on or off.

&S Turns strikethrough printing on or off.

&"fontname" Prints the characters that follow in the specified font. Be sure to include the double
quotation marks.
Format
code Description

&nn Prints the characters that follow in the specified font size. Use a two-digit number to
specify a size in points.

&color Prints the characters in the specified color. User supplies a hexadecimal color value.

&"+" Prints the characters that follow in the Heading font of the current theme. Be sure to
include the double quotation marks.

&"-" Prints the characters that follow in the Body font of the current theme. Be sure to
include the double quotation marks.

&K xx. S nn Prints the characters that follow in the specified color from the current theme.
n
xx is a two-digit number from 1 to 12 that specifies the theme color to use.

S nnn specifies the shade (tint) of that theme color. Specify S as + to produce a lighter
shade; specify S as - to produce a darker shade.

nnn is a three-digit whole number that specifies a percentage from 0 to 100.

If the values that specify the theme color or shade are not within the described limits,
Excel will use the nearest valid value.

VBA code Description

&D Prints the current date.

&T Prints the current time.

&F Prints the name of the document.

&A Prints the name of the workbook tab.

&P Prints the page number.

&P+number Prints the page number plus the specified number.


VBA code Description

&P-number Prints the page number minus the specified number.

&& Prints a single ampersand.

&N Prints the total number of pages in the document.

&Z Prints the file path.

&G Inserts an image.

You might also like