Creating modern listviews using Windows APIs (2 Viewers)

xavier.batlle

Active member
Local time
Today, 16:47
Joined
Sep 1, 2023
Messages
315
This Custom ListView System shows how to use the WINDOWS ListView control using some Windows APIs.

It’s intended to be an example not a full ready code to use on your applications, so use it at your own risk.

I know that similar behaviour can be achieved using continuous forms with conditional formating. This approach is not meant to be better or worse, it is simply another way of doing something.

1777288239237.png

CAVEATS
  • The first column is always left aligned, it can’t be changed
  • In 32 bit MS Access, Access freezes after editing the code or opening the VBE, so if the code is edited you should exit MS Access and reenter if you want avoid it.
  • This code uses Windows API subclassing so if it raises an error the application is likely to freeze.
  • This application is difficult to debug because of the subclassing calls so when debugging is very likely to freeze.
  • It is only fully compatible with MS Access 2016 onwards.
FEATURES

1. Core Control Replacement

  • VBA ListBox Enhancement: It transforms a standard, limited Access ListBox to a Windows API ListView. The position, font name, font size and if it’s bold or not of the ListBox are used to set the ListView format. Columns width must be set manually using code (in twips).
  • Dual-Architecture Support: Fully compatible with both 32-bit and 64-bit Microsoft Access
2. Visual & Aesthetic Customization
  • DPI aware. The ListView size depends on the Windows scale.
  • Row-Level Coloring: Supports specific background colors for individual rows (e.g., coloring a row red if it is "URGENT").
  • Custom Selection Theme: Overrides the default Windows "blue" selection highlight to allow for custom selection background and text colors.
  • Font Management: Allows for custom font names, sizes, and styles (bold/normal) via GDI font handles.
3. Data Interaction
  • Checkbox Support: Includes an optional checkbox column with a custom "Hand Cursor" that appears specifically when hovering over the checkbox area.
  • Selection Modes: Supports both Single-Select (one row at a time) and Multi-Select (standard Windows multiple selection).
  • Dynamic Data Loading: Easily populates data from DAO Recordsets or Arrays.
  • State Management: Procedures to CheckAll, UncheckAll, or set a specific array of rows as "checked" by default.
4. Column Management
  • Report View: Organizes data into structured columns with defined headers.
  • Alignment Control: Individual columns can be aligned Left, Right, or Center.
  • Interaction Restrictions: Optionally enables or disables the user's ability to drag-and-drop to reorder columns.
  • Columns can be resized using the mouse.
  • Auto-Sizing: Logic to force-fit columns or specifically auto-size the last column to the control width.
5. Advanced User Logic
  • Full Unicode suport.
  • Groups. Items can be assigned to a group and the group can be expanded and collapsed.
  • Header Sorting: Automatically sorts data (alphabetically or numerically) when a user double-clicks a column header, with an ascending/descending toggle.
  • Mass Deletion: Monitors the Delete key. When pressed, it can prompt the user and delete all selected rows simultaneously.
  • Custom Events: Raises a specialized AfterDelete event that returns a Collection of the Unique IDs (ColumnRowSource) of the deleted items so you can sync the deletion with your underlying database.
  • Data Extraction: Functions to retrieve checked or selected items as a Scripting Dictionary, mapping row indices to their underlying data values.
6. Updates
  • 27/04/2026 Ver.22
Initial release.​
  • 29/04/2026 Ver.23
Added full Unicode support.​
  • 01/05/2026 Ver.24
The contents of the STATUS column become hidden for the selected records after being displayed. Fixed in ver.24​
Selected items are now painted as unselected when a listbox losts its focus. Fixed in ver.24​
 

Attachments

Last edited:
What is the benefit over using a continuous form with conditional formatting? Things like the optional checkbox can be easily created….
 
Interesting work Xavier. Thanks for posting. On my machine I get a hard crash in modListViewSubclass in this routine...
Code:
Public Sub HookParentForm(ByVal hWnd As LongPtr)
    Dim m_PrevWndProc As LongPtr
    If Not p_FormInfo.Exists(CStr(hWnd)) Then
        Dim clsFormH As New clsFormHook
        
        #If Win64 Then
            m_PrevWndProc = SetWindowLongPtr(hWnd, GWL_WNDPROC, AddressOf WindowProc)
        #Else
            m_PrevWndProc = SetWindowLong(hWnd, GWL_WNDPROC, AddressOf WindowProc)
        #End If
        
•       clsFormH.m_PrevWndProc = m_PrevWndProc
        p_FormInfo.Add CStr(hWnd), clsFormH
    End If
End Sub
At the dot. It just crashes Access without preamble.

Hey also, is there anything like this you've seen that could replace a continuous form? What I would love to find in MS Access is a way to bind a format-able list control--something like a repeater control--to a collection of objects.
• I currently use an MSComCtlLib.Listview, but the row height can't be set, and you can't really re-design the row presentation. It can display custom object lists though.
• A continuous form is great, but it can only be bound to a recordset, so useless if you have a list that is not a recordset.
Cheers,
 
Interesting work Xavier. Thanks for posting. On my machine I get a hard crash in modListViewSubclass in this routine...
Code:
Public Sub HookParentForm(ByVal hWnd As LongPtr)
    Dim m_PrevWndProc As LongPtr
    If Not p_FormInfo.Exists(CStr(hWnd)) Then
        Dim clsFormH As New clsFormHook
       
        #If Win64 Then
            m_PrevWndProc = SetWindowLongPtr(hWnd, GWL_WNDPROC, AddressOf WindowProc)
        #Else
            m_PrevWndProc = SetWindowLong(hWnd, GWL_WNDPROC, AddressOf WindowProc)
        #End If
       
•       clsFormH.m_PrevWndProc = m_PrevWndProc
        p_FormInfo.Add CStr(hWnd), clsFormH
    End If
End Sub
At the dot. It just crashes Access without preamble.

Hey also, is there anything like this you've seen that could replace a continuous form? What I would love to find in MS Access is a way to bind a format-able list control--something like a repeater control--to a collection of objects.
• I currently use an MSComCtlLib.Listview, but the row height can't be set, and you can't really re-design the row presentation. It can display custom object lists though.
• A continuous form is great, but it can only be bound to a recordset, so useless if you have a list that is not a recordset.
Cheers,
Hi Mark,
Peter Thornton offers a all VBA listgrid
ListgridDemo.jpg


His Listview is a hybrid Listview and Flexgrid and is based on MSForms Controls
ListgridDemoText.jpg

Ask Peter Thornton <pmbthornton@gmail.com> for the Demo .accdb

Cheers
Bernd
 
At the dot. It just crashes Access without preamble.
You will crash if you hook your form whilst the VBA editor is open.

You need to close the editor and then run the form/code.

So, no ability to step through code whilst it runs.
 
is there anything like this you've seen that could replace a continuous form?
The web browser control has endless possibilities and it won't crash as often as unlisted controls do by default. Just an opinion.

Cheers.
 
Interesting work Xavier. Thanks for posting. On my machine I get a hard crash in modListViewSubclass in this routine...

I can't reproduce the error, so I can only suggest that you add “On Error Next” at the beginning of the 3 callback procedures, because any unhandled error causes Access to crash. (I forgot to add them before uploading the file)

Code:
Public Function ListViewProc(ByVal hWnd As LongPtr, ByVal uMsg As Long, ByVal wParam As LongPtr, ByVal lParam As LongPtr) As LongPtr
    On Error Resume Next ' To avoid an unhandled error crashes Access
    ...
End Function

Public Function WindowProc(ByVal hWnd As LongPtr, ByVal uMsg As Long, ByVal wParam As LongPtr, ByVal lParam As LongPtr) As LongPtr
    On Error Resume Next ' To avoid an unhandled error crashes Access
    ...
End function

Public Function CompareFunc(ByVal lParam1 As LongPtr, ByVal lParam2 As LongPtr, ByVal hWnd As LongPtr) As Long    ' 1. El seguro de vida para evitar que Access se cierre    On Error GoTo ErrorHandler
    On Error Resume Next ' To avoid an unhandled error crashes Access
    ...
End Function
 
Last edited:
An interesting idea but I also wonder whether it has any significant advantages over using continuous forms with conditional formatting.
I do like the grouping feature. However, once again this does require a lot of APIs and related code.
Is there sufficient benefit to justify this, particularly with all the caveats that you listed?

I haven't tested in 32-bit Access so haven't experienced the issues you describe. No crashes in 64-bit
I remember you mentioning the same problem in a previous example database. Do you know what causes the problem in 32-bit?

I know you said its not meant to be ready for deployment use. However, here are some issues that I noticed:
1. Click one or more records then click Show Checked Rows - the contents of the STATUS column become hidden for the selected records. The only way to recover that column data is to reopen the form
2. Open in Form View change to Design view and back to Form View. The ungrouped section is no longer formatted. Clicking Select All (or Toggle Selected Rows) followed by Unselect All fixes that issue
3. After flipping from Design View & Back to Form View, clicking Shrink All Groups no longer works reliably. Then click Expand All Groups, - colour formatting is lost. Click again to restore formatting
 
Peter Thornton offers a all VBA listgrid
His Listview is a hybrid Listview and Flexgrid and is based on MSForms Controls
I know Flexgrid is 32-bit only (more's the pity)
Is Peter Thornton's listgrid usable in 64-bit Access?
 

Users who are viewing this thread

Back
Top Bottom