Сортировка списков в excel vba

Сортировка данных в таблице на рабочем листе Excel средствами VBA. Sort и SortField, объекты и методы. Примеры сортировки данных в диапазоне.

Синтаксис сортировки

Синтаксис полного кода VBA Excel, применяемого для сортировки данных в таблицах и диапазонах:

With Expression.Sort

    .SortFields.Clear

    .SortFields.Add Key, SortOn, Order, DataOption

    .SetRange [Range]

    .Header = [xlGuess, xlYes, xlNo]

    .MatchCase = [True, False]

    .Orientation = [xlTopToBottom, xlLeftToRight]

    .Apply

End With

Синтаксис сокращенного кода VBA Excel, применяемого для сортировки данных с параметрами по умолчанию:

With Expression.Sort

    .SortFields.Clear

    .SortFields.Add Key

    .SetRange [Range]

    .Apply

End With

Expression – выражение, возвращающее объект Worksheet, например:

ActiveSheet

Worksheets («Лист1»)

ActiveWorkbook.Worksheets («Лист1»)

Workbooks(«Книга1.xlsm»).Worksheets («Лист1»)

Расшифровка кода

1. Expression.Sort – метод Sort объекта Worksheet возвращает объект Sort.

Объект Sort – это объект, представляющий сортировку диапазона данных.


2. .SortFields.Clear – метод SortFields объекта Sort возвращает коллекцию объектов SortFields. Метод Clear объекта SortFields удаляет все существующие объекты SortField.

Объект SortField содержит все сведения о параметрах сортировки для заданного рабочего листа.


3. .SortFields.Add Key, SortOn, Order, DataOption – метод Add объекта SortFields создает и возвращает новый экземпляр объекта SortField с заданными параметрами.

Параметры метода Add объекта SortFields:

Key – обязательный параметр, который задает значение ключа для сортировки. Тип данных – Range. Обычно указывается первая ячейка столбца при сортировке по строкам или первая ячейка строки при сортировке по столбцам. Сортировка диапазона будет осуществлена по данным столбца (строки), первая ячейка которого указана в качестве ключа.

SortOn – необязательный параметр, который задает критерий сортировки (по какому свойству ячеек производится сортировка).

Значения, которые может принимать SortOn:

Константа Значение Описание
SortOnValues 0 сортировка по значению (значение по умолчанию)
SortOnCellColor 1 сортировка по цвету ячейки
SortOnFontColor 2 сортировка по цвету шрифта
SortOnIcon 3 сортировка по иконке*

* Иконки (значки) могут быть заданы ячейкам при условном форматировании диапазона.

Order – необязательный параметр, задающий порядок сортировки (по возрастанию или по убыванию).

Значения, которые может принимать Order:

Константа Значение Описание
xlAscending 1 сортировка по возрастанию (значение по умолчанию)
xlDescending 2 сортировка по убыванию

DataOption – необязательный параметр, который задает способ сортировки текста.

Значения, которые может принимать DataOption:

Константа Значение Описание
xlSortNormal 0 числовые и текстовые данные сортируются отдельно (значение по умолчанию)
xlSortTextAsNumbers 1 текстовые данные рассматриваются для сортировки как числовые

4. .SetRange [Range] – метод SetRange объекта Sort задает диапазон (таблицу), в котором выполняется сортировка.


5. .Header = [xlGuess, xlYes, xlNo] – свойство Header объекта Sort указывает, является ли первая строка таблицы строкой заголовков (шапкой).

Значения, которые может принимать свойство Header:

Константа Значение Описание
xlGuess 0 Excel сам определяет, есть ли строка заголовков
xlYes 1 строка заголовков есть, сортировка ее не затрагивает
xlNo 2 строки заголовков нет (значение по умолчанию)

6. .MatchCase = [True, False] – свойство MatchCase объекта Sort указывает, как учитывать регистр при сортировке.

Значения, которые может принимать свойство MatchCase:

Константа Значение Описание
False 0 регистр не учитывается (значение по умолчанию)
True 1 сортировка с учетом регистра

7. .Orientation = [xlTopToBottom, xlLeftToRight] – свойство Orientation объекта Sort задает ориентацию для сортировки.

Значения, которые может принимать свойство Orientation:

Константа Значение Описание
xlTopToBottom 1 сортировка по стокам (значение по умолчанию)
xlLeftToRight 2 сортировка по столбцам

8. .Apply – метод Apply объекта Sort выполняет сортировку диапазона в соответствии с примененными параметрами.

Примеры сортировки

Таблица для примеров

Сортировка по одному столбцу

Краткая запись кода VBA Excel для сортировки диапазона по первому столбцу с параметрами по умолчанию:

Sub Primer1()

    With ActiveSheet.Sort

        .SortFields.Clear

        .SortFields.Add Key:=Range(«A2»)

        .SetRange Range(«A2:C7»)

        .Apply

    End With

End Sub

Полная запись, но тоже с параметрами по умолчанию:

Sub Primer2()

    With ActiveSheet.Sort

        .SortFields.Clear

        .SortFields.Add Key:=Range(«A2»), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal

        .SetRange Range(«A2:C7»)

        .Header = xlNo

        .MatchCase = False

        .Orientation = xlTopToBottom

        .Apply

    End With

End Sub

Результат сортировки:

Сортировка по двум столбцам

Код VBA Excel для сортировки исходной таблицы по первому и второму столбцам с параметрами по умолчанию:

Sub Primer3()

    With ActiveSheet.Sort

        .SortFields.Clear

        .SortFields.Add Key:=Range(«A2»)

        .SortFields.Add Key:=Range(«B2»)

        .SetRange Range(«A2:C7»)

        .Apply

    End With

End Sub

Результат сортировки:

Применение сортировки ко второму столбцу (добавление еще одного объекта SortField) не нарушает сортировку первого – в первом столбце меняются местами только ячейки с одинаковыми значениями.

In this Article

  • Sort Data with Excel VBA
    • Practical Use of the Sort Method in VBA
    • Sample Data to Demonstrate Excel Sorting with VBA
    • Recording a Macro for a VBA Sort
    • VBA Code to do a Single Level Sort
    • VBA Code to do a Multi-Level Sort
    • Sorting by Cell Color
    • Sorting by Font Color
    • Using Other Parameters in VBA Sorting
    • Extending the Sorting Function Using VBA

Sort Data with Excel VBA

Excel has an excellent means of sorting a range of tabular data using the ribbon on the Excel front end, and at some point, you will probably want to use this functionality within your VBA code. Fortunately, this is very easy to do.

The front-end dialog box is found by clicking the ‘Sort’ icon in the ‘Sort & Filter’ group of the ‘Data’ tab on the Excel ribbon. You need to select a range of tabular data first.

You can also use Alt-A-S-S to show the dialog box for a custom sort.

The sort method has been greatly improved in later versions of Excel. The sort used to be restricted to three levels, but you can now enter as many levels as your need, and this also applies within VBA.

PIC 01

You can incorporate all the sort functions on offer in the Excel Sort dialog into your VBA code. The sort function in Excel is fast, and quicker than anything that you could write yourself in VBA, so take advantage of the functionality.

Note that when you do a sort in VBA, the sort parameters remain the same in the front-end sort dialog box. They also are saved when the workbook is saved.

If a user selects the same range of tabular data and clicks on the Sort icon, they will see all your parameters that have been entered by your VBA code. If they want to do a sort of their own design, then they will have to delete all your sort levels first, which will be very annoying for them.

Also, if you do not change the parameters within your code, and rely on default values, you may find that the user has made changes which will reflect through into your VBA sort, and may give unexpected results, which may be very difficult to debug.

Fortunately, there is a Clear method in VBA to re-set all the sort parameters so that the user will see a clean sort dialog box

Worksheets("Sheet1").Sort.SortFields.Clear

It is good practice to clear the sort parameters in VBA before and after the sort has been completed.

Practical Use of the Sort Method in VBA

When tabular data is imported into Excel, it is often in a very random order. It could be imported from a CSV (comma separated values) file or it could come from a link to a database or web page. You cannot rely on it being in a set order from one import to another.

If you are presenting this data to a user within your worksheet, the user may well find it difficult to look at and understand a huge amount of data which in terms of order is all over the place. They may want to group the data, or cut and paste certain sections of it into another application.

They may also want to see, for example, the highest paid employee, or the employee with the longest service.

Using the Sort method in VBA, you can offer options to allow easy sorting for the user.

Sample Data to Demonstrate Excel Sorting with VBA

We first need some sample data to be entered into a worksheet, so that the code can demonstrate all the facilities available within VBA.

PIC 02

Copy this data into a worksheet (called ‘Sheet1’) exactly as shown.

Note that different cell background colors and font colors have been used, as these can also be used as sorting parameters. Sorting using cell and font colors will be demonstrated later in the article. Also note that on cell E3, the department name is all lower case.

You do not need the cell interior and font colors if you do not wish to use the examples of sorting by cell and font color.

Recording a Macro for a VBA Sort

VBA code for sorting can get quite complicated, and it can sometimes be a good idea to do the sort on the front end of Excel and record a macro to show you how the code works.

Unfortunately, the recording function can generate a huge amount of code because it sets virtually every parameter available, even though the default values for many parameters are acceptable to your sort operation.

However, it does give you a very good idea of what is involved in writing VBA sort code, and one advantage is that the recorded code will always work for you. Your own code may need testing and debugging to make it work properly.

Remember that for an operation done in VBA, there is no undo feature, so it is a good idea to make a copy of the tabular data onto another worksheet before you start writing your sorting code.

As an example, if you did a simple sort on the sample data above, sorting by Employee, the recording would generate the following code:

Sub Macro1()

Range("A1:E6").Select

ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Add2 Key:=Range("A2:A6"), _
    SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal

With ActiveWorkbook.Worksheets("Sheet1").Sort
    .SetRange Range("A1:E6")
    .Header = xlYes
    .MatchCase = False
    .Orientation = xlTopToBottom
    .SortMethod = xlPinYin
    .Apply
End With

End Sub

This is quite a large chunk of code, and a lot of it is unnecessary because of default parameters being used. However, if you are under time pressure to complete a project and you need some code quickly that works, you can easily paste this into your own VBA code.

However, if you want to make your code understandable and more elegant, then there are other options available. 

VBA Code to do a Single Level Sort

If you want to sort the sample code based on Employee only as before when recording a macro, the code is very simple:

Sub SingleLevelSort()

Worksheets("Sheet1").Sort.SortFields.Clear

Range("A1:E6").Sort Key1:=Range("A1"), Header:=xlYes

End Sub

This is far easier to understand than the recorded code because it accepts the defaults, e.g., sort ascending, so there is no need to set the parameters to default values. This assumes that you have used a ‘Clear’ statement beforehand.

The ‘Clear’ method is used initially to ensure that every sort parameter for that worksheet is set back to the default values. A user may have previously set the parameters to different values, or an earlier sort in VBA may have changed them. It is important to start from a default position when sorting, otherwise you could easily end up with incorrect results.

The Clear method does not reset the Header parameter, and it is advisable to include this in your code, otherwise Excel may try and guess whether a header row is present or not.

Run this code against the sample data and your worksheet will look like this:

PIC 03

VBA Code to do a Multi-Level Sort

You can add in as many sorting levels as required within your code. Suppose that you wished to sort first by department and then by start date but in ascending order for the department and descending order for start date:

Sub MultiLevelSort()

Worksheets("Sheet1").Sort.SortFields.Clear

Range("A1:E6").Sort Key1:=Range("E1"), Key2:=Range("C1"), Header:=xlYes, _
    Order1:=xlAscending, Order2:=xlDescending

End Sub

Note that there are now two keys in the sort statement (Key1 and Key2). Key1 (Department column E) is sorted first of all and then Key2 (Start Date column C) is sorted based on the first sort.

There are also two order parameters. Order1 associates with Key1 (Department) and Order2 associates with Key2 (Start Date). It is important to ensure that keys and orders are kept in step with each other.

Run this code against the sample data and your worksheet will look like this:

PIC 04

The Department column (E) is in ascending order, and the Start Date column (C) is in descending order.

The effect of this sort is most noticeable when looking at Jane Halfacre (row 3) and John Sutherland (row 4). They are both in Finance but Jane Halfacre started before John Sutherland and the dates are shown in descending order.

If the range of tabular data could be of any length, you can use the UsedRange object to define the sort range. This will only work if there is only the tabular data on the worksheet as any values outside of the data will give incorrect results for the number of rows and columns.

Sub MultiLevelSort()

Worksheets("Sheet1").Sort.SortFields.Clear
Worksheets("Sheet1").UsedRange.Sort Key1:=Range("E1"), Key2:=Range("C1"), Header:=xlYes, _
    Order1:=xlAscending, Order2:=xlDescending

End Sub

This prevents the problem if you use the method ‘End(xlDown)’ to define the sort range. If there is a blank cell in the middle of the data, then anything after the blank cell will not be included, whereas UsedRange goes down to the last active cell in the worksheet.

VBA Coding Made Easy

Stop searching for VBA code online. Learn more about AutoMacro — A VBA Code Builder that allows beginners to code procedures from scratch with minimal coding knowledge and with many time-saving features for all users!

automacro

Learn More

Sorting by Cell Color

Since Excel 2007, sorting by the background color of a cell is now possible, which provides enormous flexibility when designing your sort code in VBA.

Sub SingleLevelSortByCellColor()

Worksheets("Sheet1").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Add2 Key:=Range("A2:A6"), _
    SortOn:=xlSortOnCellColor, Order:=xlAscending, DataOption:=xlSortNormal

With ActiveWorkbook.Worksheets("Sheet1").Sort
    .SetRange Range("A2:E6")
    .Apply
End With

End Sub

This code will sort the sample data range (A2:A6) based on the cell background color. Note that there is now an additional parameter called ‘SortOn’ which has the value of ‘xlSortOnCellColor’.

Note that the ‘SortOn’ parameter can only be used by a worksheet object and not by a range object.

Because of this the code is more complicated than for a sort using cell values.

This code uses a key value for the sort which covers the whole range of data but you can specify individual columns as the key for the background color sort, and use multiple levels as shown earlier.

After running this code, your worksheet will now look like this:

PIC 05

Sorting by Font Color

The sort function in Excel VBA offers even more flexibility in that you can sort by font colors:

Sub SingleLevelSortByFontColor()

Worksheets("Sheet1").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Add(Range("A2:A6"), _
    xlSortOnFontColor, xlAscending, xlSortNormal).SortOnValue.Color = RGB(0, 0, 0)

With ActiveWorkbook.Worksheets("Sheet1").Sort
    .SetRange Range("A1:E6")
    .Header = xlYes
    .Orientation = xlTopToBottom
    .Apply
End With

End Sub

The code for sorting by font color is far more complicated than for the cell background color. The ‘SortOn’ parameter now holds the value of ‘xlSortOnFontColor’.

Note that you must specify orientation as ‘xlTopToBottom’ and you must specify a color to sort on. This is specified in RGB terms (Red, Green, Black) with values going from 0 to 255.

After running this code against the sample data, your worksheet will now look like this:

PIC 06

Sorting using colors in VBA is far more complicated than a multi-level sort, but if your sort code will not work (which can happen if a parameter is missing or you have not entered the code correctly) then you can always fall back on recording a macro and integrating the recorded code into your VBA.

Using Other Parameters in VBA Sorting

There are a number of optional parameters that you can use in your VBA code to customize your sort.

SortOn

SortOn chooses whether the sort will use cell values, cell background colors, or cell font colors. The default setting is Cell Values.

SortOn = xlSortOnValues

Order

Order chooses whether the sort will be done in ascending or descending order. The default is Ascending.

Order = xlAscending

DataOption

DataOption chooses how text and numbers are sorted. The parameter xlSortNormal sorts numeric and text data separately. The parameter xlSortTextAsNumbers treats text as numeric data for the sort. The default is xlSortNormal.

DataOption = xlSortNormal

Header

Header chooses whether the tabular data range has a header row or not. If there is a header row, you do not want this included in the sort.

Parameter values are xlYes, xlNo, and xlYesNoGuess. xlYesNoGuess leaves it to Excel to determine if there is a header row, which could easily lead to inconsistent results. Use of this value is not recommended.

The default value is XNo (no header row within the data). With imported data, there is usually a header row, so make sure that you set this parameter to xlYes.

Header = xlYes

MatchCase

This parameter determines whether the sort is case-sensitive or not. Option values are True or False. If the value is False, then lower case values are considered the same as upper case values. If the value is True, then the sort will show the difference between upper and lower case values within the sort. The default value is False.

MatchCase = False

Orientation

This parameter determines whether the sort will take place downwards through the rows, or across all the columns. The default value is xlTopToBottom (sort through rows). You can use xlLeftToRight if you wish to sort horizonally. Values such as xlRows and xlColumns do not work for this parameter.

Orientation = xlTopToBottom

SortMethod

This parameter is only used for sorting Chinese languages. It has two values, xlPinYin and xlStroke. xlPinYin is the default value.

xlPinYin sorts using the phonetic Chinese sort order for characters. xlStroke sorts by the quantity of strokes in each character.

If you record a sort macro, this parameter will always be included in the code, and you may well have wondered what it meant. However, unless you are dealing with data in Chinese, it is of little use.

SortMethod = xlPinYin

Using a Double-Click Event to Sort Tabular Data

In all the functionality that Microsoft included in the sort methods for VBA, it did not include a simple means to double-click on a column header and sort the whole of the tabular data based on that particular column.

This is a really useful feature to have, and it is easy to write the code to do it.

Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
'Assumption is made that data begins at cell A1

'Create three variables to capture the target column selected and the maximum column and row of _
'   the tabular data
Dim Col As Integer, RCol As Long, RRow As Long

'Check that the user has double-clicked on the header row – row 1 otherwise exit sub
If Target.Row <> 1 Then Exit Sub

'Capture the maximum rows in the tabular data range using the ‘UsedRange’ object
RCol = ActiveSheet.UsedRange.Columns.Count

'Capture the maximum columns in the tabular data range using the 'UsedRange' object
RRow = ActiveSheet.UsedRange.Rows.Count

'Check that the user has not double-clicked on a column outside of the tabular data range
If Target.Column > RCol Then Exit Sub

'Capture the column that the user has double-clicked on
Col = Target.Column

'Clear away previous sort parameters
ActiveSheet.Sort.SortFields.Clear

'Sort the tabular range as defined by maximum rows and columns from the 'UsedRange' object
'Sort the tabular data using the column double-clicked by the user as the sort key
ActiveSheet.Range(Cells(1, 1), Cells(RRow, RCol)).Sort Key1:=Cells(1, Col), Header:=xlYes

'Select cell A1 – this is to ensure that the user is not left in edit mode after the sort is _
'   completed
ActiveSheet.Range("A1").Select

End Sub

This code needs to be placed on the double-click event on the sheet containing the tabular data. You do this by clicking on the worksheet name in the Project Explorer window (top-left hand corner of the VBE screen), and then selecting ‘Worksheet’ in the first drop down on the code window. Select ‘BeforeDoubleClick’ in the second drop down, and you can then enter your code.

Note that no names, ranges, or cell references are hardcoded into this code except for moving the cursor to cell A1 at the end of the code. The code is designed to get all the information required from the cell coordinates that the user has double-clicked on and the size of the tabular data range.

It does not matter how large the tabular data range is. The code will still pick up all the required information and it can be used on data held anywhere within your workbook without having to hardcode in values.

The only assumption made is that there is a header row in the tabular data, and that the data range starts at cell A1, but the starting position for the data range can be easily changed within the code.

Any user will be suitably impressed with this new sorting functionality!

PIC 07

VBA Programming | Code Generator does work for you!

Extending the Sorting Function Using VBA

Microsoft has allowed tremendous flexibility in sorting using a wide range of parameters. However, within VBA, you can take this further.

Suppose that you wanted to sort any values with a bold font to the top of your data. There is no way to do this in Excel, but you can write the VBA code to do it:

Sub SortByBold()

'Create variables to hold the number of rows and columns for the tabular data
Dim RRow As Long, RCol As Long, N As Long

'Turn off screen updating so that the user cannot see what is happening – they may see _
'   values being altered and wonder why
Application.ScreenUpdating = False

'Capture the number of columns in the tabular data range
RCol = ActiveSheet.UsedRange.Columns.Count

'Capture the number of rows within the tabular data range
RRow = ActiveSheet.UsedRange.Rows.Count

'Iterate through all the rows in the tabular data range ignoring the header row
For N = 2 To RRow
    'If a cell has a bold font then place a leading 0 value against the cell value
    If ActiveSheet.Cells(N, 1).Font.Bold = True Then
        ActiveSheet.Cells(N, 1).Value = "0" & ActiveSheet.Cells(N, 1).Value
    End If
Next N

'Clear any previous sort parameters
ActiveSheet.Sort.SortFields.Clear

'Sort the tabular data range. All the values with a leading 0 value will move to the top
ActiveSheet.Range(Cells(1, 1), Cells(RRow, RCol)).Sort Key1:=Cells(1, 1), Header:=xlYes

'Iterate through all the rows in the tabular data range ignoring the header row
For N = 2 To RRow
    'If a cell has a bold font then remove the leading 0 value from the cell value to _
    '   restore the original values
    If ActiveSheet.Cells(N, 1).Font.Bold = True Then
        ActiveSheet.Cells(N, 1).Value = Mid(ActiveSheet.Cells(N, 1).Value, 2)
    End If
Next N

'Turn screen updating back on
Application.ScreenUpdating = True

End Sub

The code works out the size of the tabular data range using the ‘UsedRange’ object and then iterates through all the rows within it. When a bold font is found, a leading zero is placed in front of the cell value.

A sort then takes place. As the sort is in ascending order, anything with a zero in front will go to the top of the list.

The code then iterates through all the rows and removes the leading zeroes, restoring the data to its original values.

This code sorts using bold fonts as a criterion, but you could easily use other cell characteristics in the same way, e.g., italic font, point size of text, underscore font, font name, etc.

I received a question from a reader recently, who wanted to sort a Listbox using VBA.  As this seemed like a common problem which many users could face, I decided to dedicate a bit of time to create a more reusable solution.

In this post, we will look at two different types of Listboxes:

  • UserForm Listboxes for custom VBA solutions
  • Form Control Listboxes for worksheet based solutions

Sort ListBoxes with VBA

This post may seem like a lot of VBA code, but are comments inserted into the code to understand what is happening.  Within the text I included my thought process, to illustrate how I approached the scenario.  Whether my approach is right or wrong, it’s how I think about VBA.

There are four sort methods covered in this post:

  • Standard order (the order the elements are added to the list box)
  • Reverse order (the reverse of the standard order)
  • A-Z sort
  • Z-A sort

Download the workbook

Sometimes it is easier to see the solution in action.  So you can download the file by clicking the link below.

Download example workbook

Disclaimer:
Whilst I try to create safe and reliable templates and add-ins, I can (and often do) make mistakes.  Please backup copies of your files before opening any templates, add-ins or using any information you find on the site.  If you do find any bugs or errors, please let me know using my contact page.  By using any templates, add-ins, downloads or information from the site, you agree that I will not be held liable for any type of damages, and use is entirely at your own risk.

Re-usable code

One of the key principles of this little task was for the code to be as re-usable as possible.  Therefore in approaching this I sought to apply the following principles:

  • The code which performs the main actions is contained within a standard module
  • The code contained within the UserForm module intercepts the events (i.e. button clicks) then calls a macro from the standard module
  • The variables used for the macros within the standard module are passed as arguments when calling the macro
  • The list is re-created each time it is sorted, no matter which sort method is selected.  This ensures the list is updated for any changes whenever it is sorted.  The piece of reusable code which clears and re-creates the list I am calling the “resetMacro”.

Listboxes on UserForms

The screenshot below shows the UserForm, it contains:

  • a ListBox
  • four buttons for the different sort options
  • a close button

Sort ListBoxes - UserForm

VBA code included in a standard module

The following is the code to include in the standard module, which performs the main actions.

Display the UserForm

The first code, will simply display the UserForm when a button is clicked.

Sub ShowUserForm()

'Show the user form
frmListBoxExample.Show

End Sub

Populate the ListBox

The following code will list all the worksheets in a ListBox.  A variable referencing the specific ListBox is passed to the macro at run-time, therefore the code can be used with any ListBox.  In our example, this VBA code is used:

  • when the UserForm is initialized
  • when the btnStandard button is clicked
  • within all the other sort macros to recreate the list.
Sub UserFormList(myListBox As MSForms.ListBox)

'Create an object variable to hold worksheet as an object
Dim ws As Worksheet

'Clear the listBox
myListBox.Clear

'Loop through each worksheet add to listBox
For Each ws In ThisWorkbook.Worksheets

    myListBox.AddItem ws.Name

Next ws

End Sub

Reverse the items in the ListBox

The following code will first call the “resetMacro” to refresh the ListBox, then sort it in reverse order.

Sub UserFormReverseList(myListBox As MSForms.ListBox, Optional resetMacro As String)

'Create variables
Dim ListArray() As String
Dim i As Integer

'Reset the listBox into standard order
If resetMacro <> "" Then
    Run resetMacro, myListBox
End If

'Resize the Array variable
ReDim ListArray(0 To myListBox.ListCount - 1)

'Loop through the listBox and reverse the order into an Array
For i = 0 To myListBox.ListCount - 1

    ListArray(i) = myListBox.List(myListBox.ListCount - 1 - i)

Next i

'Clear the listBox
myListBox.Clear

'Fill the list box with the Array
myListBox.List = ListArray

End Sub

A-Z sort the List Box

The following code will first call the “resetMacro” to refresh the ListBox, then sort it in A-Z order using the Bubble sort method.

Sub UserFormSortAZ(myListBox As MSForms.ListBox, Optional resetMacro As String)

'Create variables
Dim j As Long
Dim i As Long
Dim temp As Variant

'Reset the listBox into standard order
If resetMacro <> "" Then
    Run resetMacro, myListBox
End If

'Use Bubble sort method to put listBox in A-Z order
With myListBox
    For j = 0 To .ListCount - 2
        For i = 0 To .ListCount - 2
            If LCase(.List(i)) > LCase(.List(i + 1)) Then
                temp = .List(i)
                .List(i) = .List(i + 1)
                .List(i + 1) = temp
            End If
        Next i
    Next j
End With

End Sub

If you notice there is a -2 in the code, which appears odd.  So why is it there and what does it do?

  • Using the Bubble Sort method, the last item does not need to be sorted.  If every other item in the list is sorted correctly, then the last item must also be in the correct place (so that is the first -1).
  • The first item in a UserForm ListBox is item 0, rather than 1.  Therefore, as the list starts at zero, we can -1 from the count to ensure we loop through all the items once.

Note: When using a Form Control list box, the first list position is 1, so the Form Control VBA code further down the post only has -1, rather than -2.

Z-A sort the ListBox

The following code will first call the “resetMacro” to refresh the ListBox, then sort it in Z-A order using the Bubble sort method.

Sub UserFormSortZA(myListBox As MSForms.ListBox, Optional resetMacro As String)

'Create variables
Dim j As Long
Dim i As Long
Dim temp As Variant

'Reset the listBox into standard order
If resetMacro <> "" Then
    Run resetMacro, myListBox
End If

'Use Bubble sort method to put listBox in Z-A order
With myListBox
    For j = 0 To .ListCount - 2
        For i = 0 To .ListCount - 2
            If LCase(.List(i)) < LCase(.List(i + 1)) Then
                temp = .List(i)
                .List(i) = .List(i + 1)
                .List(i + 1) = temp
            End If
        Next i
    Next j
End With

End Sub

VBA code included in the UserForm code module

The following sections of code are all included within the UserForm module.  The code here is primarily to call the macros in the standard module, which we covered in the section above.

The name of the ListBox in the example is lstListBox.

Initialize the UserForm

When the UserForm first opens the UserForm_Initialize code executes.  In our example, when the UserForm opens it calls the UserFormList macro, passing the lstListBox as an object variable into the macro.

Private Sub UserForm_Initialize()

Call UserFormList(Me.lstListBox)

End Sub

Clicking the btnClose Button

The close button with Unload the UserForm.

Private Sub btnClose_Click()

Unload Me

End Sub

Clicking the btnStandard button

The first button calls the macro to return the list to its original order.  The code UserFormList is called, passing the lstListBox as an object variable.

Private Sub btnStandard_Click()

Call UserFormList(Me.lstListBox)

End Sub

Clicking the btnReverse button

The second button calls the macro to reverse the order of the list.  In our example, the code UserFormReverseList is called.  Two arguments are passed (1) the ListBox object (2) the name of the resetMacro.

Private Sub btnReverse_Click()

Call UserFormReverseList(Me.lstListBox, "UserFormList")

End Sub

Clicking the btnAZ button

The third button calls the macro to sort the list in A-Z order.  The code UserFormSortAZ is called.  Two arguments are passed (1) the ListBox object (2) the name of the “resetMacro”.

Private Sub btnAZ_Click()

Call UserFormSortAZ(Me.lstListBox, "UserFormList")

End Sub

Clicking btnZA button

The fourth button calls the macro to sort the list in Z-A order.  The code UserFormSortZA is called.  Two arguments are passed (1) the ListBox object (2) the “resetMacro”.

Private Sub btnZA_Click()

Call UserFormSortZA(Me.lstListBox, "UserFormList")

End Sub

That now completes the code used to sort a ListBox contained within a UserForm.

Form Control Listboxes on the worksheet

The code in this section is for use with a Form Control ListBox.

Sort ListBoxes -FormControl

Each button is assigned to a macro requiring arguments, as a result they do not appear within the Assign Macro box.  Click here to learn more about this technique.

The macros assigned to each button is as follows:

  • Standard sort: FormControlList “lstListBox”‘
  • Reverse sort: FormControlReverse “lstListBox”, “FormControlList”‘
  • A-Z sort: FormControlSortAZ “lstListBox”, “FormControlList”‘
  • Z-A sort: FormControlSortZA “lstListBox”, “FormControlList”‘

VBA code included in a standard module

The following code is all included in the standard module.

Populate the ListBox

The code below will list all the worksheets in a ListBox.  The specific ListBox is passed to the macro as an argument, therefore this can be used with any ListBox.  This macro is called:

  • when the btnStandard button is clicked
  • within all the other sort macros to recreate the list (i.e. the “resetMacro”).
Sub FormControlList(myListBoxName As String)

'Create Object variable to hold the listBox
Dim myListBox As Object

'Set the variable to the worksheet and listBox called
Set myListBox = ActiveSheet.ListBoxes(myListBoxName)

'Create an object variable to hold worksheet as an object
Dim ws As Worksheet

'Clear the listBox
myListBox.RemoveAllItems

'Loop through each worksheet add to listBox
For Each ws In ThisWorkbook.Worksheets

    myListBox.AddItem ws.Name

Next ws

End Sub

Reverse the items in the ListBox

The following code will first call the “resetMacro” to update the ListBox, then sort it in reverse order.

Sub FormControlReverse(myListBoxName As String, Optional resetMacro As String)

'Create variables
Dim ListArray() As String
Dim i As Integer
Dim myListBox As ListBox

'Set the variable to the worksheet and listBox called
Set myListBox = ActiveSheet.ListBoxes(myListBoxName)

'Reset the listBox into standard order
If resetMacro <> "" Then
    Run resetMacro, myListBoxName
End If

'Resize the Array variable
ReDim ListArray(1 To myListBox.ListCount)

'Loop through the listBox and reverse the order into an Array
For i = 1 To myListBox.ListCount

    ListArray(i) = myListBox.List(myListBox.ListCount - i + 1)

Next i

'Clear the listBox
myListBox.RemoveAllItems

'Fill the list box with the Array
myListBox.List = ListArray

End Sub

A-Z sort the List Box

The following code will first call the “resetMacro” to update the ListBox, then sort it in A-Z order using the Bubble sort method.

Sub FormControlSortAZ(myListBoxName As String, Optional resetMacro As String)

'Create variables
Dim j As Long
Dim i As Long
Dim temp As Variant
Dim myListBox As ListBox

'Set the variable to the worksheet and listBox
Set myListBox = ActiveSheet.ListBoxes(myListBoxName)

'Reset the listBox into standard order
If resetMacro <> "" Then
    Run resetMacro, myListBoxName
End If

'Use Bubble sort method to put listBox in A-Z order
With myListBox
    For j = 1 To .ListCount - 1
        For i = 1 To .ListCount - 1
            If LCase(.List(i)) > LCase(.List(i + 1)) Then
                temp = .List(i)
                .List(i) = .List(i + 1)
                .List(i + 1) = temp
            End If
        Next i
    Next j
End With

End Sub

Z-A sort the List Box

The following code will first call the “resetMacro” to update the ListBox, then sort it in Z-A order using the Bubble sort method.

Sub FormControlSortZA(myListBoxName As String, Optional resetMacro As String)

'Create variables
Dim j As Long
Dim i As Long
Dim temp As Variant
Dim myListBox As ListBox

'Set the variable to the worksheet and listBox
Set myListBox = ActiveSheet.ListBoxes(myListBoxName)

'Reset the listBox into standard order
If resetMacro <> "" Then
    Run resetMacro, myListBoxName
End If

'Use Bubble sort method to put listBox in A-Z order
With myListBox
    For j = 1 To .ListCount - 1
        For i = 1 To .ListCount - 1
            If LCase(.List(i)) < LCase(.List(i + 1)) Then
                temp = .List(i)
                .List(i) = .List(i + 1)
                .List(i + 1) = temp
            End If
       Next i
    Next j
End With

End Sub

Conclusion

In this post, we have seen two methods to sort ListBoxes using VBA using reusable code segments.  Obviously, to be useful this needs to be part of a bigger project.  Feel free to take this and adapt it as you need to.


Headshot Round

About the author

Hey, I’m Mark, and I run Excel Off The Grid.

My parents tell me that at the age of 7 I declared I was going to become a qualified accountant. I was either psychic or had no imagination, as that is exactly what happened. However, it wasn’t until I was 35 that my journey really began.

In 2015, I started a new job, for which I was regularly working after 10pm. As a result, I rarely saw my children during the week. So, I started searching for the secrets to automating Excel. I discovered that by building a small number of simple tools, I could combine them together in different ways to automate nearly all my regular tasks. This meant I could work less hours (and I got pay raises!). Today, I teach these techniques to other professionals in our training program so they too can spend less time at work (and more time with their children and doing the things they love).


Do you need help adapting this post to your needs?

I’m guessing the examples in this post don’t exactly match your situation. We all use Excel differently, so it’s impossible to write a post that will meet everybody’s needs. By taking the time to understand the techniques and principles in this post (and elsewhere on this site), you should be able to adapt it to your needs.

But, if you’re still struggling you should:

  1. Read other blogs, or watch YouTube videos on the same topic. You will benefit much more by discovering your own solutions.
  2. Ask the ‘Excel Ninja’ in your office. It’s amazing what things other people know.
  3. Ask a question in a forum like Mr Excel, or the Microsoft Answers Community. Remember, the people on these forums are generally giving their time for free. So take care to craft your question, make sure it’s clear and concise.  List all the things you’ve tried, and provide screenshots, code segments and example workbooks.
  4. Use Excel Rescue, who are my consultancy partner. They help by providing solutions to smaller Excel problems.

What next?
Don’t go yet, there is plenty more to learn on Excel Off The Grid.  Check out the latest posts:

Excel already has a couple of ways to sort data quickly.

You can easily sort a data set by using the sort icons in the ribbon or the sort dialog box.

Sort Data options in the ribbon

Then why do you need to know how to do this using VBA?

Knowing how to sort data using VBA can be helpful when included as a part of your code. For example, suppose you get a data set daily/weekly that you need to format and sort in a specific order.

You can create a macro to do all this for you with a single click. That will save you a lot of time and effort every time you do it.

Also, if you create Excel dashboards, you can take Excel sorting capability to a new level by allowing the user to sort the data just by double-clicking on the header (as shown below).

Sort Data Using VBA - Double Click Demo

I will cover how to create this later in this tutorial. Let’s first quickly get the basics straight.

Understanding the Range.Sort Method in Excel VBA

When sorting using VBA, you need to use the Range.Sort method in your code.

The ‘Range’ would be the data that you’re trying to sort. For example, if you’re sorting the data in A1:A10, then ‘Range’ would be Range(“A1:A10”).

You can also create a named range and use it instead of the cell references. For example, if I create a named range ‘DataRange’ for the cells A1:A10, then I can also use Range(“DataRange”)

With the sort method, you need to provide some additional information through parameters. Below are the key parameters you need to know:

  • Key – here you need to specify the column that you want to sort. For example, if you want to sort column A, you need to use key:=Range(“A1”)
  • Order – here you specify whether you want the sorting in an ascending order or the descending order. For example, if you want the sorting in ascending order, you will use Order:=xlAscending
  • Header – here you specify whether your data set has headers or not. If it has headers, the sorting starts from the second row of the data set, else it starts from the first row. To specify that your data has headers, you will use Header:=xlYes

While these three suffices in most of the cases, you can read more about the parameters in this article.

Now let’s see how to use the Range.Sort method in VBA to sort data in Excel.

Sorting a Single Column Without Header

Suppose you have a single column without header (as shown below).

Data for sorting with VBA - without headers single column

You can use the below code to sort it in ascending order.

Sub SortDataWithoutHeader()
Range("A1:A12").Sort Key1:=Range("A1"), Order1:=xlAscending, Header:=xlNo
End Sub

Note that I have specified the data range manually as Range(“A1:A12”).

In case there might be changes in the data and values might be added/deleted, you can use the below code that automatically adjusts based on the filled cells in the dataset.

Sub SortDataWithoutHeader()
Range("A1", Range("A1").End(xlDown)).Sort Key1:=Range("A1"), Order1:=xlAscending, Header:=xlNo
End Sub

Note that instead of Range(“A1:A12”), I have used, Range(“A1”, Range(“A1”).End(xlDown)).

This will check the last consecutively filled cell in the column and include it in sorting. In case there are blanks, it will only consider data till the first blank cell.

You can also create a named range and use that named range instead of the cell references. For example, if the named range is DataSet, your code would now be as shown below.

Sub SortDataWithoutHeader()
Range("DataRange").Sort Key1:=Range("A1"), Order1:=xlAscending, Header:=xlNo
End Sub

Now let me quickly explain the parameters used in the above examples:

  • Key1:=Range(“A1”) – Specified A1 so that the code would know which column to sort.
  • Order1:=xlAscending – Specified the order as xlAscending. If you want it to be in the descending order, use xlDescending.
  • Header:= xlNo – Specified that there are no headers. This is also the default value. So even if you omit this, your data will be sorted considering it has no headers.

Wondering where to put this VBA code and how to run the macro? Read this tutorial!

Sorting a Single Column With Header

In the previous example, the data set did not have a header.

When your data has headers, you need to specify that in the code so that the sorting can start from the second row of the dataset.

Suppose you have a dataset as shown below:

Dataset to sort data using VBA in Excel

Below is the code that will sort the data in descending order based on the sales of the stores.

Sub SortDataWithHeader()
Range("DataRange").Sort Key1:=Range("C1"), Order1:=xlDescending
End Sub

Note that I have created a named range – ‘DataRange’, and used this named range in the code.

Sorting Multiple Columns With Headers

So far in this tutorial, we have seen how to sort a single column (with and without headers).

Now, what if you want to sort based on multiple columns.

For example, in the below data set, what if I want to first sort by the state code, and then by the store.

Dataset to sort data using VBA in Excel

Here is the code that will sort multiple columns at one go.

Sub SortMultipleColumns()
With ActiveSheet.Sort
     .SortFields.Add Key:=Range("A1"), Order:=xlAscending
     .SortFields.Add Key:=Range("B1"), Order:=xlAscending
     .SetRange Range("A1:C13")
     .Header = xlYes
     .Apply
End With
End Sub

Below is the result that you will get.

Sorting Multiple Columns Using VBA

In the above example, the data is first sorted by the state code (column A). Then within the state code data, it is again sorted by the Store (Column B). This order is determined by the code in which you mention it.

Sorting Data Using Double Click on Header

If you’re creating a dashboard or want more ease of use in your reports, you can write a VBA code that will sort the data when you double click on the headers.

Something as shown below:

Sort Data with VBA in Excel Using Double Click

Below is the code that will allow you to do this:

Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
Dim KeyRange As Range
Dim ColumnCount As Integer
ColumnCount = Range("DataRange").Columns.Count
Cancel = False
If Target.Row = 1 And Target.Column <= ColumnCount Then
Cancel = True
Set KeyRange = Range(Target.Address)
Range("DataRange").Sort Key1:=KeyRange, Header:=xlYes
End If
End Sub

Note that I have created a named range (“DataRange”) and have used it in the code instead of using the cell references.

As soon as you double-click on any of the headers, the code disables the usual double-click functionality (which is to get into the edit mode) and uses that cell as the key while sorting the data.

Also note that as of now, this code will sort all the columns in ascending order only.

Note that double-click is a trigger allows Excel to run the specified code. These triggers such as double-click, opening a workbook, adding a new worksheet, changing a cell, etc. are called events and can be used to run macros in Excel. You can read more about Excel VBA events here.

Where to put this code?

You need to paste this code into the code window of the sheet in which you want this double click sort functionality.

To do this:

  • Right-click on the sheet tab.
  • Click on View Code.
  • Paste the code in the code window of the sheet in which your data resides.

Now what if you want to sort the first two columns (‘State’ and ‘Store’) in ascending order, but ‘Sales’ column in descending order.

Here is the code that will do it:

Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
Dim KeyRange As Range
Dim ColumnCount As Integer
ColumnCount = Range("DataRange").Columns.Count
Cancel = False
If Target.Row = 1 And Target.Column <= ColumnCount Then
Cancel = True
Set KeyRange = Range(Target.Address)
If Target.Value = "Sales" Then
SortOrder = xlDescending
Else
SortOrder = xlAscending
End If
Range("DataRange").Sort Key1:=KeyRange, Header:=xlYes, Order1:=SortOrder
End If
End Sub

In the above code, it checks if the cell that is double-clicked is the Sales header or not. If yes, then it assigns the xlDescending value to the variable SortOrder, else it makes it xlAscending.

Now let’s take this a notch further and show a visual Marker (arrow and colored cell) in the header when it is sorted.

Something as shown below:

Sort Data Using VBA - Double Click Demo

To get this, I have added a new worksheet and made the following changes in it (you can download the example file and follow along):

  • Changed the name of the new sheet to ‘BackEnd’.
  • In cell B2, entered an arrow symbol (to do this, go to Insert and click on ‘Symbol’ option).
  • Copy and paste the headers from the data set to cell A3:C3 in the ‘Backend’ sheet.
  • Use the following function in cell A4:AC4:
    =IF(A3=$C$1,A3&" "&$B$1,A3)
  • Rest of the cells will automatically get filled by the VBA code when you double click on the headers to sort the column.

Your backend sheet would look something as shown below:

Sort Data using VBA - Backend for double click with arrow

Now you can use the below code to sort the data by double-clicking on the headers. When you double-click on a header, it will automatically get the arrow in the header text. Note that I have also used conditional formatting to highlight the cell as well.

Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
Dim KeyRange As Range
Dim ColumnCount As Integer
ColumnCount = Range("DataRange").Columns.Count
Cancel = False
If Target.Row = 1 And Target.Column <= ColumnCount Then
Cancel = True
Worksheets("Backend").Range("C1") = Target.Value
Set KeyRange = Range(Target.Address)
Range("DataRange").Sort Key1:=KeyRange, Header:=xlYes
Worksheets("BackEnd").Range("A1") = Target.Column
For i = 1 To ColumnCount
Range("DataRange").Cells(1, i).Value = Worksheets("Backend").Range("A4").Offset(0, i - 1).Value
Next i
End If
End Sub

Note that this code works well for the way my data and workbook is constructed. If you change the structure of the data, you will have to modify the code accordingly.

Download the Example File

You May Also Like the Following Excel Tutorials:

  • Sort Worksheets in Excel (Alphabetically)
  • How to Filter Data in a Pivot Table in Excel.
  • Dynamic Excel Filter Search Box – Extract Data as you Type.
  • How to do a Multi-level Data Sorting in Excel.
  • Excel Advanced Filter – A Complete Guide with Examples.
  • 24 Useful Excel Macro Examples for VBA Beginners.
  • How to Use Excel VBA InStr Function (with practical EXAMPLES).
  • Excel VBA Autofilter.

To sort a range of cells using VBA, you need to use the “SORT” method that allows you to set a single key (column) or multiple keys (for multiple columns) to sort. You can also define the order (ascending or descending) in which you want to sort, and you can specify if you have a header or not.

Sort a Range with VBA

  1. Use the range object to specify the range that you wish to sort.
  2. Type a dot and enter the sort method.
  3. Specify the key that you want to use to sort.
  4. Define the sorting order.
  5. Mention if you have a header or not.
Range("A1:A11").Sort Key1:=Range("A1"), _
                     Order1:=xlAscending, _
                     Header:=xlYes

In the above code, you have used the range A1:A11, and in the sort method, you have used the ascending order, mentioned that you have a header in the range.

Understanding the VBA’s Sort Method

Before you write a macro to sort a range it’s better to make deep dive into the sort method and understand its arguments.

Sort (Key1, Order1, Key2, Type, Order2, Key3, Order3, _
Header, OrderCustom, MatchCase, Orientation, SortMethod, _
DataOption1, DataOption2, DataOption3)

The following are the most important arguments that you will be using in the real life.

  • Key: Here you need to define a cell whose column you want to use as a base to sort.
  • Order: Order in which you want to sort the column (ascending/descending).
  • Header: A constant to specify if you have a header or not or you want VBA to guess.

In the following code, I have used the “xlDescending” to sort amount column using descending order.

Range("A1:A13").Sort Key1:=Range("A1"), _
                     Order1:=xlDescending, _
                     Orientation:=xlSortColumns

Using Multiple Columns (Keys) to Sort

You can also use more than one column to sort a range. Let’s take an example of the below table where you have multiple entries with employee names and cities, and you need to sort using the name and city.

Here’s the code that you need to use:

Range("A1:C13").Sort Key1:=Range("A1"), _
                     Order1:=xlAscending, _
                     Key2:=Range("B1"), _
                     Order1:=xlAscending, _
                     Header:=xlYes

As you can see in the code, you have key1 and key2. In the key1, you have the column with the employee name, and in the key2, you have the city column. For both columns, the sorting order is ascending, and headers are there.

Note: You can use it as any column you want to use to take as a sort base using the keys and order.

Changing Sort Orientation

When you normally sort data in Excel, by default, you can sort using columns. But from the sort options, you can change the sort orientation to the left to right instead of top to bottom.

In the same way, you have an argument in the sort method to change the orientation (link).

Range("A1:C13").Sort Key1:=Range("A1"), _
                     Order1:=xlAscending, _
                     Orientation:=xlSortRows

More Tutorials

    • Count Rows using VBA in Excel
    • Excel VBA Font (Color, Size, Type, and Bold)
    • Excel VBA Hide and Unhide a Column or a Row
    • Excel VBA Range – Working with Range and Cells in VBA
    • Apply Borders on a Cell using VBA in Excel
    • Find Last Row, Column, and Cell using VBA in Excel
    • Insert a Row using VBA in Excel
    • Merge Cells in Excel using a VBA Code
    • Select a Range/Cell using VBA in Excel
    • SELECT ALL the Cells in a Worksheet using a VBA Code
    • ActiveCell in VBA in Excel
    • Special Cells Method in VBA in Excel
    • UsedRange Property in VBA in Excel
    • VBA AutoFit (Rows, Column, or the Entire Worksheet)
    • VBA ClearContents (from a Cell, Range, or Entire Worksheet)
    • VBA Copy Range to Another Sheet + Workbook
    • VBA Enter Value in a Cell (Set, Get and Change)
    • VBA Insert Column (Single and Multiple)
    • VBA Named Range | (Static + from Selection + Dynamic)
    • VBA Range Offset
    • VBA Wrap Text (Cell, Range, and Entire Worksheet)
    • VBA Check IF a Cell is Empty + Multiple Cells

    ⇠ Back to What is VBA in Excel

    Helpful Links – Developer Tab – Visual Basic Editor – Run a Macro – Personal Macro Workbook – Excel Macro Recorder – VBA Interview Questions – VBA Codes

    Like this post? Please share to your friends:
  • Сортировка списка по убыванию в excel
  • Сортировка списка по столбцам excel
  • Сортировка списка по полю excel
  • Сортировка списка в microsoft excel это
  • Сортировка списка excel формула