Outlook 98-Style FlatHeader Control

This FlatHeader control is my contribution to the effort of mimicking all the new Microsoft flat style controls. Apart from the look and feel of the Outlook 98 Header control, it extends the functionality of the standard Header control with the following features:

  • Optional size constraints,
  • Optional sorting arrow (without loosing the image nor bitmap options),
  • Fixes for the FULLDRAG redraw problem (images are not properly redrawn in a standard Header control).

It should be backward compatible wit the standard Header control in most cases (even for owner drawn header items), although the current implementation lacks the following features:

  • Item Text callbacks
  • Item Image callbacks
  • Hottracking
  • RTL reading
  • Unicode (not properly tested).

Depending on the feedback and my needs, I'll extend the implementation with proper support for these features.

The control can be applied as a straight dropin replacement for the standard Header control by subclassing the standard Header control of a CListCtrl control, by overiding the PreSubclassWindow() in the CListCtrl:

void CFlatListCtrl::PreSubclassWindow() 
{
	CListCtrl::PreSubclassWindow();
	VERIFY(m_wndFlatHeader.SubclassWindow(::GetDlgItem(m_hWnd,0)));
}

Or in a CListView:

int CFlatListView::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if (CListView::OnCreate(lpCreateStruct) == -1)
		return -1;

	if (m_wndFlatHeader.SubclassWindow(GetListCtrl().GetDlgItem(0)->GetSafeHwnd()) == 0)
	{
		TRACE0("Unable to subclass header control.\n");
		return -1;
	}

	return 0;
}

Refer to the Demo project (or various CodeGuru articles) for more information on using a subclassed header control in List controls or List views.

The control is derived from CHeaderCtrl, and supports most of the functionality of this control. Refer to the platform SDK and MFC documentation for more information on using the CHeaderCtrl.

The CHeaderCtrl is extended with the following members:

	BOOL ModifyProperty(WPARAM wParam, LPARAM lParam);

	BOOL GetItemEx(INT iPos, HDITEMEX* phditemex) const;
	BOOL SetItemEx(INT iPos, HDITEMEX* phditemex);

	void SetSortColumn(INT iPos, BOOL bSortAscending);
	INT GetSortColumn(BOOL* pbSortAscending = NULL);
	INT GetDropResult();

ModifyProperty allows you to modify a property of the control. wParam specifies the property, lParam the new value of that property. 

wParam (Property) lParam (Data)
FH_PROPERTY_SPACING Text/image/bitmap/arrow spacing
FH_PROPERTY_ARROW size of the sorting arrow, use the MAKELPARAM macro with the arrow's cx value in wLow and the arrow's cy value in wHigh.
FH_PROPERTY_STATICBORDER if lParam is other then 0, the control adjusts it's layout for CListCtrls that use the static border style.
FH_PROPERTY_DONTDROPCURSOR The resource ID of the cursor to be displayed when the user drops a header item outside the header control or drop target.
FH_PROPERTY_DROPTARGET The handle of the window the user can drop a header item to.

GetItemEx/SetItemEx allow you to get or set the extended features of a Header item, much like the GetItem member of the standard control, however, the functions do not require you specify a mask. Currently the extended item structure only contains the minimum and maximum width of an item. If the maximum size is smaller then the minimum size, there will be no size constraints. These members may be used in future versions to add more per item properties.

GetSortColumn/SetSortColumn allow you to get or set the item that will display a sort arrow. iPos identifies the item that will display the sort arrow, setting iPos to -1 removes the sort arrow. bSortAscending specifies the order (and is optional in the GetSortColumn).

GetDropResult indicates whether the drop occured in the control (0), in the drop target(1) or outside the control or the drop target (-1).

Version history:

1.0.0.1	- Initial release
1.0.1.0	- Fixed FHDragWnd destroy warning (thanks Philippe Terrier)
	- Fixed double sent HDN_ITEMCLICK
	- Added a property that adjusts for ListCtrls that use a static
	  border for flat look.
	- Added sample list view support.
1.0.2.0	- Fixed another destroy warning
	- Fixed InsertItem array exception handling
	- Fixed incorrect header width painting
	- Changed DrawItem argument passing
	- Changed HDITEMEX struct item names
	- Added handler for HDM_SETIMAGELIST (precalculate image dimensions)
	- Changed DrawImage to clip images
	- Changed InsertItem ASSERT check to position limitation
	- Added new-style "HotDivider" arrows
	- Fixed some GDI objects
	- Added 'don't drop cursor' support to indicate drag&drop 
	  outside control
	- Added drag&drop target window support
	- Changed CFHDragWnd to support externally created items
	- Removed topmost-style from CFHDropWnd
	- Fixed OnSetHotDivider order bug
	- Added extended styles
	- Added item width estimation function

The control uses Keith Rules MemDC class for flicker free drawing.

Environment: VC6, Windows 98, NT4 (IE4).

Enjoy!

Downloads

Download demo project - 48 KB
Download source - 11 KB


Comments

  • Dietary Supplementation Improve Your Flourishing Living

    Posted by Ascephept on 02/07/2013 08:49pm

    is a wonderful diet pill as well as fat-burner which improves the entire body's rate of metabolism. It not just stops working fat, but it does not burn muscular tissue - problems frequently related to different fat burning products. Try Phen375 Vimax no Brasil, Buy Phen375, vigrx plus, Vimax

    Reply
  • Bug Fix(?): Bug in dragging header

    Posted by Legacy on 02/19/2003 12:00am

    Originally posted by: Jaeyoun Yi


    As Ruan commented before,
    pressing 'alt+tab' in the middle of dragging column causes some invalid operation.

    In addtion, I found the same kind of problem when resizing column headers very oftenly!!!


    Now I've resolved these problems.

    First, add a message handler for WM_CAPTURECHANGE as Ruan commented.


    void CFlatHeaderCtrl::OnCaptureChanged(CWnd *pWnd)
    {
    // TODO: Add your message handler code here
    if ( m_bDragging && pWnd->GetSafeHwnd () != GetSafeHwnd() ) //simulate Onlbuttonup messae
    {
    CPoint pt;
    ::GetCursorPos( &pt );
    this->ScreenToClient( &pt );
    OnLButtonUp( 0, pt );
    }

    CHeaderCtrl::OnCaptureChanged(pWnd);
    }


    Notice the above code is slightly different from Ruan's code!


    And secondly, add the following line in the first part of CFlatHeaderCtrl::OnMouseMove(..)


    if ( m_nClickFlags & MK_LBUTTON && m_iHotIndex >= 0 )
    {
    if ( m_bResizing )
    {
    CHeaderCtrl::OnMouseMove( nFlags, point );
    return; // <<------ Add this !!!!!
    }


    Regards,
    Jaeyoun Yi, in Korea.

    Reply
  • How to set the heder from right to left

    Posted by Legacy on 01/09/2002 12:00am

    Originally posted by: Oren Farber

    hi

    I need to create an application that use hebrew.
    I want to set the ListCtrl header from right to left

    Thaks,
    Oren

    Reply
  • How can I get it to sort a listview?

    Posted by Legacy on 10/14/2001 12:00am

    Originally posted by: Tanky

    I got it to show the arrow in a listview but can't get the column header click to fire.

    Reply
  • I can't resize the column size

    Posted by Legacy on 10/11/2001 12:00am

    Originally posted by: loner_cn

    Hi, after I subclass the class, the column size change to fixed and can't change, and also their is no comments mark before "ON_MESSAGE(HDM_INSERTITEMW, OnInsertItem)", how can I do?
    And, when I click the edge of second column, and drag it, the name on the drag image is the name of first column.


    By the way, I use this class by subclass it using this way:

    OnInitDialog() {
    CHeaderCtrl* pHeader = NULL;
    pHeader = m_list.GetHeaderCtrl(); //m_list is a CListCtrl
    if (pHeader != NULL){
    VERIFY(m_flat_HeaderCtrl.SubclassWindow(pHeader->m_hWnd));
    }
    }
    It works OK except I can't resize the column size.

    Reply
  • bug if press alt + tab when dragging the header item

    Posted by Legacy on 08/11/2001 12:00am

    Originally posted by: kingbo Ruan

    when i dragging the header item, i press the keys' alt + tab', when i repeat to come back, something wrong with
    the dragging. i resolve this problem by adding message
    'wm_capturechange'

    void CFlatHeaderCtrl::OnCaptureChanged(CWnd *pWnd)
    {
    // TODO: Add your message handler code here
    if(m_bDragging && pWnd->GetSafeHwnd () != GetSafeHwnd())//simulate Onlbuttonup messae
    OnLButtonUp(0, CPoint(0, 0));
    CHeaderCtrl::OnCaptureChanged(pWnd);
    }

    Reply
  • Errors - Does it work in VC 5?

    Posted by Legacy on 06/02/1999 12:00am

    Originally posted by: b@ckflip

    Hi,
    I'm using your class in a VC 5 project and I was wondering if your class works with VC 5? Or does VC 6 have functions that VC 5 don't have and that your class is using... These are the errors I get:

    error C2065: 'OrderToIndex' : undeclared identifier

    error C2065: 'GetItemRect' : undeclared identifier

    error C2065: 'GetImageList' : undeclared identifier

    error C2440: 'initializing' : cannot convert from 'int' to 'class CImageList*'
    Conversion from integral type to pointer type requires reinterpret_cast, C-style cast or function-style cast

    error C2065: 'GetOrderArray' : undeclared identifier

    error C2065: 'SetOrderArray' : undeclared identifier

    Help!
    b@ckflip

    Reply
  • using with a clistview?

    Posted by Legacy on 02/22/1999 12:00am

    Originally posted by: jonathan

    How would I use this flat header control with a clistview derived clistctrl?

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • On-demand Event Event Date: September 10, 2014 Modern mobile applications connect systems-of-engagement (mobile apps) with systems-of-record (traditional IT) to deliver new and innovative business value. But the lifecycle for development of mobile apps is also new and different. Emerging trends in mobile development call for faster delivery of incremental features, coupled with feedback from the users of the app "in the wild." This loop of continuous delivery and continuous feedback is how the best mobile …

  • Packaged application development teams frequently operate with limited testing environments due to time and labor constraints. By virtualizing the entire application stack, packaged application development teams can deliver business results faster, at higher quality, and with lower risk.

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds