Header in excel vba

Tables are one of the most powerful features of Excel.  Controlling them using VBA provides a way to automate that power, which generates a double benefit 🙂

Excel likes to store data within tables.  The basic structural rules, such as (a) headings must be unique (b) only one header row allowed, make tables compatible with more complex tools.  For example, Power Query, Power Pivot, and SharePoint lists all use tables as either a source or an output.  Therefore, it is clearly Microsoft’s intention that we use tables.

However, the biggest benefit to the everyday Excel user is much simpler; if we add new data to the bottom of a table, any formulas referencing the table will automatically expand to include the new data.

Whether you love tables as much as I do or not, this post will help you automate them with VBA.

Tables, as we know them today, first appeared in Excel 2007.  This was a replacement for the Lists functionality found in Excel 2003.  From a VBA perspective, the document object model (DOM) did not change with the upgraded functionality.  So, while we use the term ‘tables’ in Excel, they are still referred to as ListObjects within VBA.

Download the example file

I recommend you download the example file for this post.  Then you’ll be able to work along with examples and see the solution in action, plus the file will be useful for future reference.

Download Icon
Download the file: 0009 VBA tables and ListObjects.zip

Structure of a table

Before we get deep into any VBA code, it’s useful to understand how tables are structured.

Range & Data Body Range

The range is the whole area of the table.

VBA tables - range

The data body range only includes the rows of data, it excludes the header and totals.

VBA tables - data body range

Header and total rows

The header row range is the top row of the table containing the column headers.

VBA tables - header row range

The totals row range, if displayed, includes calculations at the bottom of the table.

VBA tables - totals row range

List columns and list rows

The individual columns are known as list columns.

VBA tables - list columns

Each row is known as a list row.

VBA tables - list rows

The VBA code in this post details how to manage all these table objects.

Referencing the parts of a table

While you may be tempted to skip this section, I recommend you read it in full and work through the examples.  Understanding Excel’s document object model is the key to reading and writing VBA code.  Master this, and your ability to write your own VBA code will be much higher.

Many of the examples in this first section use the select method, this is to illustrate how to reference parts of the table.  In reality, you would rarely use the select method.

Select the entire table

The following macro will select the whole table, including the totals and header rows.

Sub SelectTable()

ActiveSheet.ListObjects("myTable").Range.Select

End Sub

Select the data within a table

The DataBodyRange excludes the header and totals sections of the table.

Sub SelectTableData()

ActiveSheet.ListObjects("myTable").DataBodyRange.Select

End Sub

Get a value from an individual cell within a table

The following macro retrieves the table value from row 2, column 4, and displays it in a message box.

Sub GetValueFromTable()

MsgBox ActiveSheet.ListObjects("myTable").DataBodyRange(2, 4).value

End Sub

Select an entire column

The macro below shows how to select a column by its position, or by its name.

Sub SelectAnEntireColumn()

'Select column based on position
ActiveSheet.ListObjects("myTable").ListColumns(2).Range.Select

'Select column based on name
ActiveSheet.ListObjects("myTable").ListColumns("Category").Range.Select

End Sub

Select a column (data only)

This is similar to the macro above, but it uses the DataBodyRange to only select the data; it excludes the headers and totals.

Sub SelectColumnData()

'Select column data based on position
ActiveSheet.ListObjects("myTable").ListColumns(4).DataBodyRange.Select

'Select column data based on name
ActiveSheet.ListObjects("myTable").ListColumns("Category").DataBodyRange.Select

End Sub

Select a specific column header

This macro shows how to select the column header cell of the 5th column.

Sub SelectCellInHeader()

ActiveSheet.ListObjects("myTable").HeaderRowRange(5).Select

End Sub

Select a specific column within the totals section

This example demonstrates how to select the cell in the totals row of the 3rd column.

Sub SelectCellInTotal()

ActiveSheet.ListObjects("myTable").TotalsRowRange(3).Select

End Sub

Select an entire row of data

The macro below selects the 3rd row of data from the table.

NOTE – The header row is not included as a ListRow.  Therefore, ListRows(3) is the 3rd row within the DataBodyRange, and not the 3rd row from the top of the table.

Sub SelectRowOfData()

ActiveSheet.ListObjects("myTable").ListRows(3).Range.Select

End Sub

Select the header row

The following macro selects the header section of the table.

Sub SelectHeaderSection()

ActiveSheet.ListObjects("myTable").HeaderRowRange.Select

End Sub

Select the totals row

To select the totals row of the table, use the following code.

Sub SelectTotalsSection()

ActiveSheet.ListObjects("myTable").TotalsRowRange.Select

End Sub

OK, now we know how to reference the parts of a table, it’s time to get into some more interesting examples.

Creating and converting tables

This section of macros focuses on creating and resizing tables.

Convert selection to a table

The macro below creates a table based on the currently selected region and names it as myTable.  The range is referenced as Selection.CurrentRegion, but this can be substituted for any range object.

If you’re working along with the example file, this macro will trigger an error, as a table called myTable already exists in the workbook.  A new table will still be created with a default name, but the VBA code will error at the renaming step.

Sub ConvertRangeToTable()

tableName As String
Dim tableRange As Range

Set tableName = "myTable"
Set tableRange = Selection.CurrentRegion
ActiveSheet.ListObjects.Add(SourceType:=xlSrcRange, _
    Source:=tableRange, _
    xlListObjectHasHeaders:=xlYes _
    ).Name = tableName

End Sub

Convert a table back to a range

This macro will convert a table back to a standard range.

Sub ConvertTableToRange()

ActiveSheet.ListObjects("myTable").Unlist

End Sub

NOTE – Unfortunately, when converting a table to a standard range, the table formatting is not removed.  Therefore, the cells may still look like a table, even when they are not – that’s frustrating!!!

Resize the range of the table

To following macro resizes a table to cell A1 – J100.

Sub ResizeTableRange()

ActiveSheet.ListObjects("myTable").Resize Range("$A$1:$J$100")

End Sub

Table styles

There are many table formatting options, the most common of which are shown below.

Change the table style

Change the style of a table to an existing pre-defined style.

Sub ChangeTableStyle()

ActiveSheet.ListObjects("myTable").TableStyle = "TableStyleLight15"

End Sub

To apply different table styles, the easiest method is to use the macro recorder.  The recorded VBA code will include the name of any styles you select.

Get the table style name

Use the following macro to get the name of the style already applied to a table.

Sub GetTableStyleName()

MsgBox ActiveSheet.ListObjects("myTable").TableStyle

End Sub

Apply a style to the first or last column

The first and last columns of a table can be formatted differently using the following macros.

Sub ColumnStyles()

'Apply special style to first column
ActiveSheet.ListObjects("myTable").ShowTableStyleFirstColumn = True

'Apply special style to last column
ActiveSheet.ListObjects("myTable").ShowTableStyleLastColumn = True

End Sub

Adding or removing stripes

By default, tables have banded rows, but there are other options for this, such as removing row banding or adding column banding.

Sub ChangeStripes()

'Apply column stripes
ActiveSheet.ListObjects("myTable").ShowTableStyleColumnStripes = True

'Remove row stripes
ActiveSheet.ListObjects("myTable").ShowTableStyleRowStripes = False

End Sub

Set the default table style

The following macro sets the default table style.

Sub SetDefaultTableStyle()

'Set default table style
ActiveWorkbook.DefaultTableStyle = "TableStyleMedium2"

End Sub

Looping through tables

The macros in this section loop through all the tables on the worksheet or workbook.

Loop through all tables on a worksheet

If we want to run a macro on every table of a worksheet, we must loop through the ListObjects collection.

Sub LoopThroughAllTablesWorksheet()

'Create variables to hold the worksheet and the table
Dim ws As Worksheet
Dim tbl As ListObject

Set ws = ActiveSheet
'Loop through each table in worksheet
For Each tbl In ws.ListObjects

    'Do something to the Table....

Next tbl

End Sub

In the code above, we have set the table to a variable, so we must refer to the table in the right way.  In the section labeled ‘Do something to the table…, insert the action to be undertaken on each table, using tbl to reference the table.

For example, the following will change the table style of every table.

tbl.TableStyle = "TableStyleLight15"

Loop through all tables in a workbook

Rather than looping through a single worksheet, as shown above, the macro below loops through every table on every worksheet.

Sub LoopThroughAllTablesWorkbook()

'Create variables to hold the worksheet and the table
Dim ws As Worksheet
Dim tbl As ListObject

'Loop through each worksheet
For Each ws In ActiveWorkbook.Worksheets

    'Loop through each table in worksheet
    For Each tbl In ws.ListObjects

        'Do something to the Table....

    Next tbl

Next ws

End Sub

As noted in the section above, we must refer to the table using its variable.  For example, the following will display the totals row for every table.

tbl.ShowTotals = True

Adding & removing rows and columns

The following macros add and remove rows, headers, and totals from a table.

Add columns into a table

The following macro adds a column to a table.

Sub AddColumnToTable()

'Add column at the end
ActiveSheet.ListObjects("myTable").ListColumns.Add

'Add column at position 2
ActiveSheet.ListObjects("myTable").ListColumns.Add Position:=2
End Sub

Add rows to the bottom of a table

The next macro will add a row to the bottom of a table

Sub AddRowsToTable()

'Add row at bottom
ActiveSheet.ListObjects("myTable").ListRows.Add

'Add row at the first row
ActiveSheet.ListObjects("myTable").ListRows.Add Position:=1
End Sub

Delete columns from a table

To delete a column, it is necessary to use either the column index number or the column header.

Sub DeleteColumnsFromTable()

'Delete column 2
ActiveSheet.ListObjects("myTable").ListColumns(2).Delete

'Delete a column by name
ActiveSheet.ListObjects("myTable").ListColumns("Feb").Delete
End Sub

Delete rows from a table

In the table structure, rows do not have names, and therefore can only be deleted by referring to the row number.

Sub DeleteRowsFromTable()

'Delete row 2
ActiveSheet.ListObjects("myTable").ListRows(2).Delete

'Delete multiple rows
ActiveSheet.ListObjects("myTable").Range.Rows("4:6").Delete
End Sub

Add total row to a table

The total row at the bottom of a table can be used for calculations.

Sub AddTotalRowToTable()

'Display total row with value in last column
ActiveSheet.ListObjects("myTable").ShowTotals = True

'Change the total for the "Total Column" to an average
ActiveSheet.ListObjects("myTable").ListColumns("TotalColumn").TotalsCalculation = _
    xlTotalsCalculationAverage

'Totals can be added by position, rather than name
ActiveSheet.ListObjects("myTable").ListColumns(2).TotalsCalculation = _
    xlTotalsCalculationAverage
End Sub

Types of totals calculation

xlTotalsCalculationNone
xlTotalsCalculationAverage
xlTotalsCalculationCount
xlTotalsCalculationCountNums
xlTotalsCalculationMax
xlTotalsCalculationMin
xlTotalsCalculationSum
xlTotalsCalculationStdDev
xlTotalsCalculationVar

Table header visability

Table headers can be turned on or off.   The following will hide the headers.

Sub ChangeTableHeader()

ActiveSheet.ListObjects("myTable").ShowHeaders = False

End Sub

Remove auto filter

The auto filter can be hidden.  Please note, the table header must be visible for this code to work.

Sub RemoveAutoFilter()

ActiveSheet.ListObjects("myTable").ShowAutoFilterDropDown = False

End Sub

I have a separate post about controlling auto filter settings – check it out here.  Most of that post applies to tables too.

Other range techniques

Other existing VBA techniques for managing ranges can also be applied to tables.

Using the union operator

To select multiple ranges, we can use VBA’s union operator. Here is an example, it will select rows 4, 1, and 3.

Sub SelectMultipleRangesUnionOperator()

Union(ActiveSheet.ListObjects("myTable").ListRows(4).Range, _
    ActiveSheet.ListObjects("myTable").ListRows(1).Range, _
    ActiveSheet.ListObjects("myTable").ListRows(3).Range).Select

End Sub

Assign values from a variant array to a table row

To assign values to an entire row from a variant array, use code similar to the following:

Sub AssignValueToTableFromArray()

'Assing values to array (for illustration)
Dim myArray As Variant
myArray = Range("A2:D2")

'Assign values in array to the table
ActiveSheet.ListObjects("myTable").ListRows(2).Range.Value = myArray

End Sub

Reference parts of a table using the range object

Within VBA, a table can be referenced as if it were a standard range object.

Sub SelectTablePartsAsRange()

ActiveSheet.Range("myTable[Category]").Select

End Sub

Counting rows and columns

Often, it is useful to count the number of rows or columns.  This is a good method to reference rows or columns which have been added.

Counting rows

To count the number of rows within the table, use the following macro.

Sub CountNumberOfRows()

Msgbox ActiveSheet.ListObjects("myTable").ListRows.Count

End Sub

Counting columns

The following macro will count the number of columns within the table.

Sub CountNumberOfColumns()

Msgbox ActiveSheet.ListObjects("myTable").ListColumns.Count

End Sub

Useful table techniques

The following are some other useful VBA codes for controlling tables.

Show the table data entry form

If a table starts at cell A1, there is a simple data entry form that can be displayed.

Sub ShowDataEntryForm()

'Only works if Table starts at Cell A1
ActiveSheet.ShowDataForm

End Sub

The following screenshot shows the data form for the example table.

Tables data input screen

Check if a table exists

The following macro checks if a table already exists within a workbook.  Change the tblName variable to adapt this to your requirements.

Sub CheckIfTableExists()

'Create variables to hold the worksheet and the table
Dim ws As Worksheet
Dim tbl As ListObject
Dim tblName As String
Dim tblExists As Boolean

tblName = "myTable"

'Loop through eac worksheet
For Each ws In ActiveWorkbook.Worksheets

    'Loop through each table in worksheet
    For Each tbl In ws.ListObjects

        If tbl.Name = tblName Then

            tblExists = True

        End If

    Next tbl

Next ws

If tblExists = True Then

    MsgBox "Table " & tblName & " exists."

Else

    MsgBox "Table " & tblName & " does not exists."

End If

End Sub

Find out if a table has been selected, if so which

The following macros find the name of the selected table.

Method 1

As you will see in the comments Jon Peltier had an easy approach to this, which has now become my preferred approach.

Sub SimulateActiveTable()

Dim ActiveTable As ListObject

On Error Resume Next
Set ActiveTable = ActiveCell.ListObject
On Error GoTo 0

'Confirm if a cell is in a Table
If ActiveTable Is Nothing Then
    MsgBox "Select table and try again"
Else
    MsgBox "The active cell is in a Table called: " & ActiveTable.Name
End If

End Sub

Method 2

This option, which was my original method, loops through each table on the worksheet and checks if they intersect with the active cell.

Sub SimulateActiveTable_Method2()

Dim ActiveTable As ListObject
Dim tbl As ListObject

'Loop through each table, check if table intersects with active cell
For Each tbl In ActiveSheet.ListObjects

    If Not Intersect(ActiveCell, tbl.Range) Is Nothing Then

        Set ActiveTable = tbl
        MsgBox "The active cell is in a Table called: " & ActiveTable.Name
    
    End If

Next tbl

'If no intersection then no tabl selected
If ActiveTable Is Nothing Then

    MsgBox "Select an Excel table and try again"

End If

End Sub

Conclusion

Wow!  That was a lot of code examples. 

There are over 30 VBA macros above, and even this does not cover everything, but hopefully covers 99% of your requirements. For your remaining requirements, you could try Microsoft’s VBA object reference library (https://docs.microsoft.com/en-us/office/vba/api/Excel.ListObject)


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:

Is it possible to set up the headers in a multicolumn listbox without using a worksheet range as the source?

The following uses an array of variants which is assigned to the list property of the listbox, the headers appear blank.

Sub testMultiColumnLb()
    ReDim arr(1 To 3, 1 To 2)

    arr(1, 1) = "1"
    arr(1, 2) = "One"
    arr(2, 1) = "2"
    arr(2, 2) = "Two"
    arr(3, 1) = "3"
    arr(3, 2) = "Three"


    With ufTestUserForm.lbTest
        .Clear
        .ColumnCount = 2
        .List = arr
    End With

    ufTestUserForm.Show 1
End Sub

Excellll's user avatar

Excellll

5,5494 gold badges38 silver badges55 bronze badges

asked Mar 18, 2009 at 9:16

vzczc's user avatar

Here is my approach to solve the problem:

This solution requires you to add a second ListBox element and place it above the first one.

Like this:

Add an additional ListBox

Then you call the function CreateListBoxHeader to make the alignment correct and add header items.

Result:

Call the function CreateListBoxHeader

Code:

  Public Sub CreateListBoxHeader(body As MSForms.ListBox, header As MSForms.ListBox, arrHeaders)
            ' make column count match
            header.ColumnCount = body.ColumnCount
            header.ColumnWidths = body.ColumnWidths

        ' add header elements
        header.Clear
        header.AddItem
        Dim i As Integer
        For i = 0 To UBound(arrHeaders)
            header.List(0, i) = arrHeaders(i)
        Next i

        ' make it pretty
        body.ZOrder (1)
        header.ZOrder (0)
        header.SpecialEffect = fmSpecialEffectFlat
        header.BackColor = RGB(200, 200, 200)
        header.Height = 10

        ' align header to body (should be done last!)
        header.Width = body.Width
        header.Left = body.Left
        header.Top = body.Top - (header.Height - 1)
End Sub

Usage:

Private Sub UserForm_Activate()
    Call CreateListBoxHeader(Me.listBox_Body, Me.listBox_Header, Array("Header 1", "Header 2"))
End Sub

answered Apr 13, 2017 at 0:21

Jonas_Hess's user avatar

Jonas_HessJonas_Hess

1,8241 gold badge20 silver badges32 bronze badges

4

No. I create labels above the listbox to serve as headers. You might think that it’s a royal pain to change labels every time your lisbox changes. You’d be right — it is a pain. It’s a pain to set up the first time, much less changes. But I haven’t found a better way.

answered Mar 18, 2009 at 15:54

Dick Kusleika's user avatar

Dick KusleikaDick Kusleika

32.5k4 gold badges51 silver badges73 bronze badges

2

I was looking at this problem just now and found this solution. If your RowSource points to a range of cells, the column headings in a multi-column listbox are taken from the cells immediately above the RowSource.

Using the example pictured here, inside the listbox, the words Symbol and Name appear as title headings. When I changed the word Name in cell AB1, then opened the form in the VBE again, the column headings changed.

Screenshot displaying a named range and the column headings outside the range.

The example came from a workbook in VBA For Modelers by S. Christian Albright, and I was trying to figure out how he got the column headings in his listbox :)

answered Mar 5, 2014 at 20:55

Rick Henderson's user avatar

1

Simple answer: no.

What I’ve done in the past is load the headings into row 0 then set the ListIndex to 0 when displaying the form. This then highlights the «headings» in blue, giving the appearance of a header. The form action buttons are ignored if the ListIndex remains at zero, so these values can never be selected.

Of course, as soon as another list item is selected, the heading loses focus, but by this time their job is done.

Doing things this way also allows you to have headings that scroll horizontally, which is difficult/impossible to do with separate labels that float above the listbox. The flipside is that the headings do not remain visible if the listbox needs to scroll vertically.

Basically, it’s a compromise that works in the situations I’ve been in.

answered Mar 18, 2009 at 9:29

Lunatik's user avatar

LunatikLunatik

3,8286 gold badges37 silver badges52 bronze badges

2

There is very easy solution to show headers at the top of multi columns list box.
Just change the property value to «true» for «columnheads» which is false by default.

After that Just mention the data range in property «rowsource» excluding header from the data range and header should be at first top row of data range then it will pick the header automatically and you header will be freezed.

if suppose you have data in range «A1:H100» and header at «A1:H1» which is the first row then your data range should be «A2:H100» which needs to mention in property «rowsource» and «columnheads» perperty value should be true

Regards,
Asif Hameed

answered Dec 13, 2016 at 18:38

Asif Hameed's user avatar

1

Just use two Listboxes, one for header and other for data

  1. for headers — set RowSource property to top row e.g. Incidents!Q4:S4

  2. for data — set Row Source Property to Incidents!Q5:S10

SpecialEffects to «3-frmSpecialEffectsEtched»
enter image description here

answered Feb 21, 2020 at 1:01

Bhanu Sinha's user avatar

Bhanu SinhaBhanu Sinha

1,51612 silver badges10 bronze badges

1

I like to use the following approach for headers on a ComboBox where the CboBx is not loaded from a worksheet (data from sql for example). The reason I specify not from a worksheet is that I think the only way to get RowSource to work is if you load from a worksheet.

This works for me:

  1. Create your ComboBox and create a ListBox with an identical layout but just one row.
  2. Place the ListBox directly on top of the ComboBox.
  3. In your VBA, load ListBox row1 with the desired headers.
  4. In your VBA for the action yourListBoxName_Click, enter the following code:

    yourComboBoxName.Activate`
    yourComboBoxName.DropDown`
    
  5. When you click on the listbox, the combobox will drop down and function normally while the headings (in the listbox) remain above the list.

pableiros's user avatar

pableiros

14.4k12 gold badges98 silver badges104 bronze badges

answered Dec 14, 2016 at 18:47

RR_CodeSlinger's user avatar

1

I was searching for quite a while for a solution to add a header without using a separate sheet and copy everything into the userform.

My solution is to use the first row as header and run it through an if condition and add additional items underneath.

Like that:

If lborowcount = 0 Then
 With lboorder
 .ColumnCount = 5
 .AddItem
 .Column(0, lborowcount) = "Item"
 .Column(1, lborowcount) = "Description"
 .Column(2, lborowcount) = "Ordered"
 .Column(3, lborowcount) = "Rate"
 .Column(4, lborowcount) = "Amount"
 End With
 lborowcount = lborowcount + 1
End If
        
        
With lboorder
 .ColumnCount = 5
 .AddItem
 .Column(0, lborowcount) = itemselected
 .Column(1, lborowcount) = descriptionselected
 .Column(2, lborowcount) = orderedselected
 .Column(3, lborowcount) = rateselected
 .Column(4, lborowcount) = amountselected
 
 
 End With

lborowcount = lborowcount + 1

in that example lboorder is the listbox, lborowcount counts at which row to add the next listbox item. It’s a 5 column listbox. Not ideal but it works and when you have to scroll horizontally the «header» stays above the row.

answered Nov 2, 2018 at 12:17

J. G.'s user avatar

J. G.J. G.

111 bronze badge

Here’s my solution.

I noticed that when I specify the listbox’s rowsource via the properties window in the VBE, the headers pop up no problem. Its only when we try define the rowsource through VBA code that the headers get lost.

So I first went a defined the listboxes rowsource as a named range in the VBE for via the properties window, then I can reset the rowsource in VBA code after that. The headers still show up every time.

I am using this in combination with an advanced filter macro from a listobject, which then creates another (filtered) listobject on which the rowsource is based.

This worked for me

answered Dec 24, 2018 at 12:54

JamesSA's user avatar

Another variant on Lunatik’s response is to use a local boolean and the change event so that the row can be highlighted upon initializing, but deselected and blocked after a selection change is made by the user:

Private Sub lbx_Change()

    If Not bHighlight Then

        If Me.lbx.Selected(0) Then Me.lbx.Selected(0) = False

    End If

    bHighlight = False

End Sub

When the listbox is initialized you then set bHighlight and lbx.Selected(0) = True, which will allow the header-row to initialize selected; afterwards, the first change will deselect and prevent the row from being selected again…

answered Apr 23, 2013 at 20:33

ChE Junkie's user avatar

ChE JunkieChE Junkie

3262 silver badges9 bronze badges

Here’s one approach which automates creating labels above each column of a listbox (on a worksheet).

It will work (though not super-pretty!) as long as there’s no horizontal scrollbar on your listbox.

Sub Tester()
Dim i As Long

With Me.lbTest
    .Clear
    .ColumnCount = 5
    'must do this next step!
    .ColumnWidths = "70;60;100;60;60"
    .ListStyle = fmListStylePlain
    Debug.Print .ColumnWidths
    For i = 0 To 10
        .AddItem
        .List(i, 0) = "blah" & i
        .List(i, 1) = "blah"
        .List(i, 2) = "blah"
        .List(i, 3) = "blah"
        .List(i, 4) = "blah"
    Next i

End With

LabelHeaders Me.lbTest, Array("Header1", "Header2", _
                     "Header3", "Header4", "Header5")

End Sub

Sub LabelHeaders(lb, arrHeaders)

    Const LBL_HT As Long = 15
    Dim T, L, shp As Shape, cw As String, arr
    Dim i As Long, w

    'delete any previous headers for this listbox
    For i = lb.Parent.Shapes.Count To 1 Step -1
        If lb.Parent.Shapes(i).Name Like lb.Name & "_*" Then
            lb.Parent.Shapes(i).Delete
        End If
    Next i

    'get an array of column widths
    cw = lb.ColumnWidths
    If Len(cw) = 0 Then Exit Sub
    cw = Replace(cw, " pt", "")
    arr = Split(cw, ";")

    'start points for labels
    T = lb.Top - LBL_HT
    L = lb.Left

    For i = LBound(arr) To UBound(arr)
        w = CLng(arr(i))
        If i = UBound(arr) And (L + w) < lb.Width Then w = lb.Width - L
        Set shp = ActiveSheet.Shapes.AddShape(msoShapeRectangle, _
                                         L, T, w, LBL_HT)
        With shp
            .Name = lb.Name & "_" & i
            'do some formatting
            .Line.ForeColor.RGB = vbBlack
            .Line.Weight = 1
            .Fill.ForeColor.RGB = RGB(220, 220, 220)
            .TextFrame2.TextRange.Characters.Text = arrHeaders(i)
            .TextFrame2.TextRange.Font.Size = 9
            .TextFrame2.TextRange.Font.Fill.ForeColor.RGB = vbBlack
        End With
        L = L + w
    Next i
End Sub

answered Feb 27, 2015 at 8:06

Tim Williams's user avatar

Tim WilliamsTim Williams

150k8 gold badges96 silver badges124 bronze badges

1

You can give this a try. I am quite new to the forum but wanted to offer something that worked for me since I’ve gotten so much help from this site in the past. This is essentially a variation of the above, but I found it simpler.

Just paste this into the Userform_Initialize section of your userform code. Note you must already have a listbox on the userform or have it created dynamically above this code. Also please note the Array is a list of headings (below as «Header1», «Header2» etc. Replace these with your own headings. This code will then set up a heading bar at the top based on the column widths of the list box. Sorry it doesn’t scroll — it’s fixed labels.

More senior coders — please feel free to comment or improve this.

    Dim Mywidths As String
    Dim Arrwidths, Arrheaders As Variant
    Dim ColCounter, Labelleft As Long
    Dim theLabel As Object                

    [Other code here that you would already have in the Userform_Initialize section]

    Set theLabel = Me.Controls.Add("Forms.Label.1", "Test" & ColCounter, True)
            With theLabel
                    .Left = ListBox1.Left
                    .Top = ListBox1.Top - 10
                    .Width = ListBox1.Width - 1
                    .Height = 10
                    .BackColor = RGB(200, 200, 200)
            End With
            Arrheaders = Array("Header1", "Header2", "Header3", "Header4")

            Mywidths = Me.ListBox1.ColumnWidths
            Mywidths = Replace(Mywidths, " pt", "")
            Arrwidths = Split(Mywidths, ";")
            Labelleft = ListBox1.Left + 18
            For ColCounter = LBound(Arrwidths) To UBound(Arrwidths)
                        If Arrwidths(ColCounter) > 0 Then
                                Header = Header + 1
                                Set theLabel = Me.Controls.Add("Forms.Label.1", "Test" & ColCounter, True)

                                With theLabel
                                    .Caption = Arrheaders(Header - 1)
                                    .Left = Labelleft
                                    .Width = Arrwidths(ColCounter)
                                    .Height = 10
                                    .Top = ListBox1.Top - 10
                                    .BackColor = RGB(200, 200, 200)
                                    .Font.Bold = True
                                End With
                                 Labelleft = Labelleft + Arrwidths(ColCounter)

                        End If
             Next

answered May 8, 2018 at 13:36

Peter Winn's user avatar

This is a bummer. Have to use an intermediate sheet to put the data in so Excel knows to grab the headers. But I wanted that workbook to be hidden so here’s how I had to do the rowsource.
Most of this code is just setting things up…

Sub listHeaderTest()
Dim ws As Worksheet
Dim testarr() As String
Dim numberOfRows As Long
Dim x As Long, n As Long

'example sheet
Set ws = ThisWorkbook.Sheets(1)
'example headers
For x = 1 To UserForm1.ListBox1.ColumnCount
    ws.Cells(1, x) = "header" & x
Next x
'example array dimensions
numberOfRows = 15
ReDim testarr(numberOfRows, UserForm1.ListBox1.ColumnCount - 1)
'example values for the array/listbox
For n = 0 To UBound(testarr)
    For x = 0 To UBound(testarr, 2)
        testarr(n, x) = "test" & n & x
    Next x
Next n

'put array data into the worksheet
ws.Range("A2").Resize(UBound(testarr), UBound(testarr, 2) + 1) = testarr

'provide rowsource
UserForm1.ListBox1.RowSource = "'[" & ws.Parent.Name & "]" & ws.Name & "'!" _
& ws.Range("A2").Resize(ws.UsedRange.Rows.Count - 1, ws.UsedRange.Columns.Count).Address

UserForm1.Show

End Sub

answered Apr 22, 2021 at 22:44

John's user avatar

For scrolling, one idea is to create a simulated scroll bar which would shift the entire listbox left and right.

  1. ensure the list box is set to full width so the horizontal scroll
    bar doesn’t appear (wider than the space available, or we wouldn’t
    need to scroll)
  2. add a scroll bar control at the bottom but with .left and .width to
    match the available horizontal space (so not as wide as the too-wide listbox)
  3. calculate the distance you need to scroll as the difference between
    the width of the extended list box and the width of the available
    horizontal space
  4. set .Min to 0 and .Max to the amount you need to scroll
  5. set .LargeChange to make the slider-bar wider (I could only get it
    to be half of the total span)

For this to work, you’d need to be able to cover left and right of the intended viewing space with a frame so that the listbox can pass underneath it and preserve any horizontal framing in the form. This turn out to be challenging, as getting a frame to cover a listbox seems not to work easily. I gave up at that point but am sharing these steps for posterity.

answered Sep 1, 2021 at 5:03

Mark E.'s user avatar

Mark E.Mark E.

3432 silver badges8 bronze badges

I found a way that seems to work but it can get messy the more complicated your code gets if you’re dynamically clearing the range after every search or changing range.

Spreadsheet:

A    B       C  

1   LName    Fname 

2   Smith    Bob  

set rng_Name = ws_Name.range("A1", ws_Name.range("C2").value 
    
lstbx.Main.rowsource = rng_Name.Address

This will loads the Headers into the listbox and allow you to scroll.

Most importantly, if you’re looping through your data and your range comes up empty, then your listbox won’t load the headers correctly, so you will have to account for no «matches».

SandPiper's user avatar

SandPiper

2,7765 gold badges32 silver badges49 bronze badges

answered Nov 4, 2022 at 13:37

Bob Smith's user avatar

Why not just add Labels to the top of the Listbox and if changes are needed, the only thing you need to programmatically change are the labels.

answered Jun 16, 2016 at 20:31

Jim's user avatar

1

If you want to insert certain information in the header / footer of the worksheet like the file name / file path or the current date or page number, you can do so using the below code.  If it is just one worksheet you can do it manually, but if it is multiple sheets or all sheets in the workbook which need this information to populated, you can do this using a simple vba macro / code.

This sample macro will insert a header/footer in every worksheet in the active workbook.  It will also insert the complete path to the workbook.

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

To copy this code to your workbook, press Alt + F11 on your keyboard. Then on the left hand side, you will see Microsoft Excel Objects.  Right click and select Insert.  Then click on Module and copy this code to the code window on the right.

Lets break up each part of the code –

We start with the usual Dim statement where we declare the variables.  In this case, we have only 1 variable – ws for the worksheet. Then we disable screen updating.

Now, in the FOR loop, we loop through each worksheet in the workbook which contains the macro. And we setup each parameter in Page Setup.  &P, &N, &D, &T, &F and &A are certain format codes which can be applied to headers & footers. &P prints the page number.  &N prints the total number of pages in the document. &D prints the current date.  &T prints the current time. &F prints the name of the document and &A prints the name of the workbook tab.

At the end we set the worksheet to nothing and free the object and enable screen updating.

Here are 2 pictures.  The 1st one shows you the header and the 2nd one the footer after the macro has been run.

img1

The header has the label Company Name.  The name is not entered in yet since we haven’t linked it to any cell or fed in any text for the Company Name.  If you enter anything in the code or in the excel sheet and reference it, then the name will be picked up and populated here.

Page # of 0 shows that currently we have 0 pages in the file, since we have run this code on a blank file.  If you run this code on a file containing data, it will show you the page number.

Printed <Date><Time> gives you the date and time the macro was run along with the text “Printed”.

img2

In the Footer, the Path label will show you the path of the current file.

Our filename is Book1.xlsx which is currently an unsaved file. Hence there is no path showing up for the Path label.

The Sheet number is populated to the right of the footer.

If you liked our blogs, share it with your friends on Facebook. And also you can follow us on Twitter and Facebook.
We would love to hear from you, do let us know how we can improve, complement or innovate our work and make it better for you. Write us at info@exceltip.com

In this article we will look at an example of how to transform columns into headers and sub-headers using Excel VBA.

Example 1:

So, let’s say you have a monthly expense report like this in a sheet called Expenses.

And you need to transform the columns Wages, Lease and Office Supplies into sub-headers for each month, in a format like this into a sheet called Output

Here is how we can achieve this. First we get the last row on the expense sheet so that we can loop through each row, as shown below:

 Set expenseSheet = Sheets(&amp;amp;quot;Expenses&amp;amp;quot;)
 Set outputSheet = Sheets(&amp;amp;quot;Output&amp;amp;quot;)

 'Get the last row from the expense sheet
 lastExpenseRow = expenseSheet.Cells(Rows.Count, 1).End(xlUp).Row

 For currentExpenseRow = 2 To lastExpenseRow

'Actual code goes here

Next currentExpenseRow

Next, within the for loop, for each row we get the number of columns. Most of the times, this will be same for all rows and can be hard-coded outside the for loop (as we have done in the next example).

 'get the number of columns in the current row
 noOfCols = expenseSheet.Cells(currentExpenseRow, Columns.Count).End(xlToLeft).Column

Then, get the row number to paste into.

 '+2 so that a blank &amp;lt;a href="https://software-solutions-online.com/insert-rows-vba/" &amp;gt;row is inserted&amp;lt;/a&amp;gt; between two months
 rowToPaste = outputSheet.Cells(Rows.Count, 2).End(xlUp).Row + 2

Note: As we will be leaving a blank row in between 2 months, we are using + 2 at the end instead of + 1

While transforming data, we will first copy the name of the month

 'copy the month name
 expenseSheet.Cells(currentExpenseRow, 1).Copy Destination:=outputSheet.Cells(rowToPaste, 1)

The actual expenses will be pasted from the next row, so increment the counter

 'increment the row on the output sheet
 rowToPaste = rowToPaste + 1

For all the remaining columns (the expense columns), we will copy the expense header and the expense data from each column (of the respective month) and paste in the subsequent rows (for that month), like this

'For all the remaining expense columns
For colNo = 2 To noOfCols

'First copy the expense header
expenseSheet.Cells(1, colNo).Copy Destination:=outputSheet.Cells(rowToPaste, 1)

'And then the actual expenses for the corresponding month
expenseSheet.Cells(currentExpenseRow, colNo).Copy Destination:=outputSheet.Cells(rowToPaste, 2)

rowToPaste = rowToPaste + 1
Next colNo

Here is the entire code put together.

Sub colToHeaders()

Dim expenseSheet As Worksheet, outputSheet As Worksheet
Dim currentExpenseRow As Long, lastExpenseRow As Long, rowToPaste As Long
Dim noOfCols As Long, colNo As Long

Set expenseSheet = Sheets(&amp;amp;quot;Expenses&amp;amp;quot;)
Set outputSheet = Sheets(&amp;amp;quot;Output&amp;amp;quot;)

'get the last row from the expense sheet
lastExpenseRow = expenseSheet.Cells(Rows.Count, 1).End(xlUp).Row

For currentExpenseRow = 2 To lastExpenseRow

With expenseSheet

'get the number of columns in the current row
noOfCols = .Cells(currentExpenseRow, Columns.Count).End(xlToLeft).Column

'+2 so that a blank &lt;a href="https://software-solutions-online.com/insert-rows-vba/"&gt;row is inserted&lt;/a&gt; between two months
rowToPaste = outputSheet.Cells(Rows.Count, 2).End(xlUp).Row + 2

'copy the month name
.Cells(currentExpenseRow, 1).Copy Destination:=outputSheet.Cells(rowToPaste, 1)

'increment the row on the output sheet
rowToPaste = rowToPaste + 1

'For all the remaining expense columns
For colNo = 2 To noOfCols

'First copy the expense header
.Cells(1, colNo).Copy Destination:=outputSheet.Cells(rowToPaste, 1)

'And then the actual expenses for the corresponding month
.Cells(currentExpenseRow, colNo).Copy Destination:=outputSheet.Cells(rowToPaste, 2)

rowToPaste = rowToPaste + 1
Next colNo

End With

Next currentExpenseRow
End Sub

Example 2:

Let us look at how to do the reverse — that is — you have data in headers and sub-headers format like this in the expenses sheet,

And you want to convert it into column format like this in the output sheet

Here we will assume that each month has exactly same sub-headers below it. The code is pretty similar to the above one and hence, the explanation is provided in the comments itself, in code below.

Sub headersToCol()

Dim expenseSheet As Worksheet, outputSheet As Worksheet
 Dim currentExpenseRow As Long, lastExpenseRow As Long, rowToPaste As Long
 Dim noOfCols As Long, colNo As Long

 Set expenseSheet = Sheets(&amp;amp;quot;Expenses&amp;amp;quot;)
 Set outputSheet = Sheets(&amp;amp;quot;Output&amp;amp;quot;)

 'get the last row from the expense sheet
 lastExpenseRow = expenseSheet.Cells(Rows.Count, 1).End(xlUp).Row

 'This is the number of sub-headers under each month
 noOfCols = 3

 'Loop through each row on the expense sheet
 For currentExpenseRow = 3 To lastExpenseRow

 With expenseSheet

 'Get the row to paste into the output sheet
 rowToPaste = outputSheet.Cells(Rows.Count, 1).End(xlUp).Row + 1

 'copy the month name
 .Cells(currentExpenseRow, 1).Copy Destination:=outputSheet.Cells(rowToPaste, 1)

 'increment the row on the output sheet as the expense data starts from the next row
 currentExpenseRow = currentExpenseRow + 1

 'For each of the expense columns below every month
 'We are looping till noOfCols + 1 as the expense columns start from column 2
 For colNo = 2 To noOfCols + 1

 'Copy the actual expenses for the corresponding month
 .Cells(currentExpenseRow, 2).Copy Destination:=outputSheet.Cells(rowToPaste, colNo)

 'Go to the next expense row
 currentExpenseRow = currentExpenseRow + 1

 Next colNo

 End With

 'Increment for the next month
 rowToPaste = rowToPaste + 1

 Next currentExpenseRow
End Sub

Thus, we can easily do column to headers / sub-headers transformation and vice-versa using the two example codes above. What’s the next step? Let’s say you want to take these values and output them to Word, then click to find out more.

Skip to content

Exceldome

Exceldome

This tutorial shows how to insert the sheet name into a header in a specific sheet using Excel and VBA

EXCEL METHOD 1. Insert sheet name into header

EXCEL

VBA METHOD 1. Insert sheet name into header using VBA

VBA

Sub Insert_sheet_name_header()

‘declare a variable

Dim ws As Worksheet

Set ws = Worksheets(«Sheet1»)

With ws.PageSetup

.CenterHeader = «&A»

End With

End Sub

NOTES
Note 1: This VBA code will insert the sheet name into the center header area of «Sheet1».

Related Topic Description Related Topic and Description
Insert a header How to insert a header
Insert a footer How to insert a footer in a specific sheet
Insert current date into header How to insert the current date into a header in a specific sheet
Insert page numbers into header How to insert page numbers into a header in a specific sheet

Like this post? Please share to your friends:
  • Having a word with someone
  • Having a good memory word
  • Haven t heard a word
  • Have you not heard that the bird is the word
  • Have you not heard about the word