Changing row height in owner drawn control


When you change the font of a list view control, the control or its parent window does not get a chance to respecify the height of the rows. No WM_MEASUREITEM message is sent to the controls parent window. The net effect is that when the font is changed for the control, the row height is no longer valid.

Here's a work around that forces the WM_MEASUREITEM message to be generated.

Step 1: Add handler for WM_SETFONT

The WM_MEASUREITEM message is sent when the control is created. Fortunately this message is also sent whenever the control is resized. Since we want the row height to be adjusted when the font changes, what better place to do thin than in the WM_SETFONT handler. In OnSetFont() we fool Windows into thinking that the window size of the control has changed. We do this by sending the WM_WINDOWPOSCHANGED message to the control which then gets handled by the default window procedure for the control. Note that we haven't specified the SWP_NOSIZE flag and we set the width and height field in the WINDOWPOS structure equal to the existing dimension.

For some reason, the Class Wizard did not have the WM_SETFONT message in its list of window messages. You will have to add the message map entry yourself. It is important to place the entries outside of the block used by the Class Wizard, otherwise the next you make any change with the wizard, our manual changes will be lost.

// In the header file
	//{{AFX_MSG(CMyListCtrl)
	:
	:
	//}}AFX_MSG
	afx_msg LRESULT OnSetFont(WPARAM wParam, LPARAM);
	afx_msg void MeasureItem ( LPMEASUREITEMSTRUCT lpMeasureItemStruct );
	DECLARE_MESSAGE_MAP()


//////////////////////////////////////////////////////////////////////
// In the cpp file
BEGIN_MESSAGE_MAP(CMyListCtrl, CListCtrl)
	//{{AFX_MSG_MAP(CMyListCtrl)
	:
	:
	//}}AFX_MSG_MAP
	ON_MESSAGE(WM_SETFONT, OnSetFont)
	ON_WM_MEASUREITEM_REFLECT( )
END_MESSAGE_MAP()


LRESULT CMyListCtrl::OnSetFont(WPARAM wParam, LPARAM)
{
	LRESULT res =  Default();

	CRect rc;
	GetWindowRect( &rc );

	WINDOWPOS wp;
	wp.hwnd = m_hWnd;
	wp.cx = rc.Width();
	wp.cy = rc.Height();
	wp.flags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER;
	SendMessage( WM_WINDOWPOSCHANGED, 0, (LPARAM)&wp );

	return res;
}

Step 2: Add handler for WM_MEASUREITEM

Since we want our CListCtrl derived class to be modular, we will handle the WM_MEASUREITEM message within this class. The message however, is sent to the parent window, so we use message reflection. Again, the Class Wizard is not much help. We have to manually add the entry in the message map and update the header file. See the code snippet in step one for this.
void CMyListCtrl::MeasureItem ( LPMEASUREITEMSTRUCT lpMeasureItemStruct )
{
	LOGFONT lf;
	GetFont()->GetLogFont( &lf );

	if( lf.lfHeight < 0 )
		lpMeasureItemStruct->itemHeight = -lf.lfHeight; 
	else
		lpMeasureItemStruct->itemHeight = lf.lfHeight; 
}



Comments

  • down

    Posted by yaodebo on 10/11/2006 02:29am

    where to download

    • I'am Minh Tiz

      Posted by minhtiz on 08/02/2008 09:03pm

      Thanks very much!

      Reply
    Reply
  • Row height calculation is not correct. You need to account for external leading.

    Posted by Legacy on 02/23/2004 12:00am

    Originally posted by: A Lee

    You'll find that the row height calculation, as shown, is not quite enough.  This will be evident when your rows are cut off.
    
    

    The problem is that lf.lfHeight gives the height of the font WITHOUT accounting for what is called "external leading," which represents the extra pixels required to write out characters like p and q that have pixels falling under the font's baseline. To get this external leading value, you need to use GetTextMetrics. Just replace the above row height calculation code with the following:

    void MyListCtrl::MeasureItem(LPMEASUREITEMSTRUCT lpmis)
    {
    CClientDC dc(this);
    TEXTMETRIC tm;

    dc.SelectObject(GetFont());
    dc.GetTextMetrics(&tm);

    lpmis->itemHeight = tm.tmHeight + tm.tmExternalLeading;
    }

    Reply
  • How to use

    Posted by Legacy on 12/30/2003 12:00am

    Originally posted by: zxj721

    I Have Insert these Codes in my programe, but I don't know how to use it,thanks

    Reply
  • Szekely Balazs's approach really works! (see the post below)

    Posted by Legacy on 09/26/2003 12:00am

    Originally posted by: Li Zhaoming

    Szekely BalazsSzekely Balazs's approach really works! (see the post below)

    Reply
  • Easy change of height without the ownerdraw shit

    Posted by Legacy on 05/09/2003 12:00am

    Originally posted by: Szekely Balazs

    Use two imaglists:
    ......
    //In definition file:
    CImageList m_imageList1;
    CImageList m_imageList2;
    long m_height1;
    long m_height2;
    CListCtrl m_list;
    ....
    //Somewhere at initialization, m_height1 and m_height2
    //contains the desired heights
    m_height1 = 10;
    m_height2 = 10;

    m_imageList1.Create(1,m_height1,ILC_COLOR4,1,1);
    m_imageList2.Create(1,m_height2,ILC_COLOR4,1,1);
    .....
    //Togle the item height by caling
    m_list.SetImageList(&m_imageList1,LVSIL_SMALL);
    //or
    m_list.SetImageList(&m_imageList2,LVSIL_SMALL);

    //The image index can be set to -1, of the image lists
    //contains some images.

    • How about Report View

      Posted by AliRafiee on 01/25/2005 03:09pm

      How about report view?

      Reply
    Reply
  • Need Demo code

    Posted by Legacy on 01/14/2003 12:00am

    Originally posted by: steven

    I can't insert item,why?

    Reply
  • Another Way to Set row height of list Ctrl

    Posted by Legacy on 08/06/2002 12:00am

    Originally posted by: cuihp

    A Simple way:
    Depend on A ImageList,you can create a ImageList thus:
    CImageList m_ImageList;
    m_ImageList.Create(1,20,ILC_COLOR,1,1);
    Second parameter '20',will decide the row height.

    Inside ListView:
    CListCtrl& lc = GetListCtrl();
    lc.SetImageList(&m_ImageList,LVSIL_SMALL);

    That's All.cuihp

    Reply
  • If no WM_MEASUREITEM message

    Posted by Legacy on 07/15/2002 12:00am

    Originally posted by: Steve Prescott

    If you do not recieve the WM_MEASUREITEM message after doing all of this, you are in the same boat I was. I was programing in Modula II, but some of you may have the same problem. If I SendMessage WM_WINDOWPOSCHANGED, or MoveWindow and I don't actually move the window, I don't recieve the WM_MEASUREITEM message. My solution was to move the window just a bit and then just move it right back. It may not be the best solution, but it worked, and I didn't see any flashing so I was happy.

    Reply
  • ListCtrl Height Problem

    Posted by Legacy on 05/31/2002 12:00am

    Originally posted by: Rajesh

    hi,

    How do i increase the row height. i am adding the ( LPMEASUREITEMSTRUCT lpMeasureItemStruct ). even though it cant increase the height. how i can do that

    any help...

    thanks,
    regards,
    Rajesh. S

    Reply
  • Factly, you only keep in mind WM_MEASUREITEM is a message send when listctrl has been created.

    Posted by Legacy on 04/26/2002 12:00am

    Originally posted by: VCLover_cn

    If you want to and now can't receive WM_MEASUREITEM ,you can Send some messages such as WM_WINDOWPOSCHANGED to intrige this message. So,you can use FuncToMEASUREITEM() in any time such as initializing listctrl header or items,but you must keep in mind WM_MEASUREITEM is a message sent when listctrl has been , FuncToMEASUREITEM() must be used when your listctrl have been created. Thanks.

    FuncToMEASUREITEM()
    {
    //...
    SendMessage( WM_WINDOWPOSCHANGED, 0, (LPARAM)&wp );
    //...
    }

    Reply
  • Loading, Please Wait ...

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

Top White Papers and Webcasts

  • For many organizations, moving enterprise applications to the public cloud can be a very attractive proposition, but planning the best way to move your applications is mission–critical. As an alternative to the costly option of re–architecting the application for a cloud environment, you can follow a "lift and shift" model that's significantly cheaper and almost always a lot quicker. In order to have a successful "lift and shift" migration, read this white paper to learn a few rules you should …

  • Microsoft® Office 365 is a top choice for enterprises that want a cloud–based suite of productivity collaboration applications. With Office 365, you get access to Microsoft™ Office solutions practically anytime, anywhere, on virtually any device. It's a great option for current Microsoft users who can now build on their experience with Microsoft™ solutions while enjoying the flexibility of a cloud-based delivery. But even organizations with no previous investment in Microsoft will find that …

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date