Download the Flat Header Class and Demo (16kb)
Before you Begin
This project requires the SSubTmr.DLL component. Make sure you have loaded and registered this before trying the project.
One feature I've been getting more and more requests for is a way of creating a flat
header like the one in the Tasks window of DevStudio version 6.
The sample project presents a class which does this to great effect, and works with
all controls using the COMCTL32.DLL header control as well as the VB6 header control
implemented in MSCOMCTL.OCX.
How it Works
As is usual with Microsoft, the flat header in the DevStudio task list is not actually implemented
using a COMCTL32.DLL window. The DevStudio task list is actually a window of class "RTaskList"
which includes the header in the same window as the rest of the grid. I guess having the source
code to all controls available (and an all but unlimited development budget) makes it a bit easier
to create windows like this from scratch!
The flat header code is encapsulated into a class called cFlatHeader. The first method is a
method to attach the class to the correct window handle so it can subclass the WM_PAINT message.
Since most controls do not expose a hWnd property for the Header control, the class uses the
FindWindowEx API method to detect whether the supplied window has a child of the
correct type. The header control will have one of the following classes:
Investigating the COMCTL32.DLL documentation at MSDN shows that there is no style you can turn
on for a header control to get the flat effect. The same effect can be achieved, however, by intercepting
the WM_PAINT message for the Header control after it has completed painting and then
drawing over the existing 3D border so the control has a thinner 3D border, as shown in the
||COMCTL32.DLL header controls; Microsoft's VB5 ListView control (COMCTL32.OCX); vbAccelerator S-Grid and Header control. Note that this class name is valid for both ANSI and Unicode versions of the control.
||Microsoft's VB6 ListView control (MSCOMCTL.OCX)
Having obtained a Window handle, intercepting the WM_PAINT message is achieved by using the
Subclassing and Timer Assistant. Setting the MsgResponse
property to emrPreProcess ensures that the control processes all paint messages first and then
the class gets the message.
Finally, the code processes WM_PAINT messages by overdrawing the borders as shown above. This code
is a bit tedious, the only important parts of the code are to note that you get the hDC of the
control to draw into using the GetDC method, and to make sure that if you call GetDC
you don't forget to subsequently call ReleaseDC!
Using the Class
This is the simple bit! Just reference SSubTmr.DLL from your project (choose Project->References and
then pick "Subclassing and Timer Assistant (with multi-control support and timer bugfix)" ) and then
add cFlatHeader to your project.
With this in place you only need two lines of code in the form containing the control you want to
have a flat header:
Private m_cFH As New cFlatHeader
Private Sub Form_Load()
The same code applies to the ListView in VB5 or VB6, the S-Grid control
and the Header control. Subsequent releases of the S-Grid control
will include this code (and also future Owner-Draw header modifications to improve the reliability of the
header bitmap and icon rendering).