Table of Contents
2001-10-10 Inserted example "multiline.zip" from Danielle.
2001-09-27 Created article
This article is a close adaption of the article
"Changing row height in
owner drawn control" at Codeguru. I've enhanced as much as I can while trying to
keep as much original content as possible. I also included a summary of the
article's comments.
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
"http://msdn.microsoft.com/library/en-us/winui/combobox_85d9.asp">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
The code in the following steps uses MFC and its class
CListCtrl.
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
"http://msdn.microsoft.com/library/en-us/winui/windows_7v90.asp">WM_SETFONT
handler. In
"http://msdn.microsoft.com/library/en-us/vcmfc98/html/_mfc_cwnd.3a3a.setfont.asp">OnSetFont()
we fool Windows into thinking that the
window size of the control has changed.
We do this by sending the
"http://msdn.microsoft.com/library/en-us/winui/windows_5q90.asp">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
"http://msdn.microsoft.com/library/en-us/winui/windows_8oz6.asp">WINDOWPOS
structure equal to the existing dimension.
In the header file:
:
:
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)
:
:
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;
}
So far the steps, adapted from the original article. Following is a summary
of the most interesting comments at the original article. The comments include
fixes and corrections to the previous steps. Since I want to leave the article
as it is, I decided to not include suggested fixes in the code fragments
above. It's up to you to use
or not to use them. Another reason is, that I don't know whether all suggested
fixes are correct. Please drop a comment here so that I can remove/adjust any
errors.
Proper implementation of MeasureItem()
routine
Problem/Solution:
When setting the row height for the CListCtrl
derived object in the
MeasureItem()
routine, you shouldn't use the lfHeight
member of the LOGFONT
structure. This value is a logical point size value, not a physical pixels
value. With different screen resolutions and larger font values, the row height
will still be wrong. The following code shows an example for implementing the
MeasureItem()
routine that should work for all of these cases, and produces the
exact same height as the default implementation.
void CMyListCtrl::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
TEXTMETRIC tm;
HDC hDC = ::GetDC(NULL);
CFont* pFont = GetFont();
HFONT hFontOld = (HFONT)SelectObject(hDC, pFont->GetSafeHandle());
GetTextMetrics(hDC, &tm);
lpMeasureItemStruct->itemHeight = tm.tmHeight + tm.tmExternalLeading + 1;
SelectObject(hDC, hFontOld);
::ReleaseDC(NULL, hDC);
}
(Paul Geringer, 1999-04-06 )
I don't receive a WM_SETFONT
or WM_MEASUREITEM
message
Problem:
I don't receive a WM_SETFONT
or WM_MEASUREITEM
message.
(Damian Williams, 1999-10-18)
Solution:
- Modify the style of the list control to "owner draw fixed" (
LVS_OWNERDRAWFIXED
).
- Overload
CListCtrlEx::DrawItem()
.
- A
WM_MEASUREITEM
message will be sent to a parent window of list control.
(Chung Hyun, Lee, 2000-05-25)
Solution 2:
Class Wizard does not show you the =WM_MEASUREITEM
reflected message. If you
use Class Wizard to get WM_MEASUREITEMS
, it can only be handled by a class other
than the list view control, i.e. a parent window. This is not satisfactory. To get a
reflected message you must add the following in the message map in your .CPP
file:
ON_WM_MEASUREITEM_REFLECT()
Then you must add the following in your header file message map:
afx_msg void MeasureItem( LPMEASUREITEMSTRUCT lpMeasureItemStruct );
then add the following function in your .CPP file:
void CMyListCtrl::MeasureItem ( LPMEASUREITEMSTRUCT lpMeasureItemStruct )
{
AfxMessageBox("You just received a WM_MEASUREITEM message");
}
(Dominic Gamble, 2000-01-13)
Solution 3:
First you must create the list view control with the style
LVS_OWNERDRAWFIXED
. Then, change the control's size, using the
CWnd::MoveWindow()
or
CWnd::SetWindowPos()
function.
It works both with hand-made-controls (using call a call to CListCtrl::Create()
) and
template-made-controls (using the resource editor)
(Gon (Jung-gon, Kim),
2000-08-09)
Changing the height of a row without using LVS_OWNERDRAWFIXED
Problem/Solution:
You can easily change the row height by making the image list icon size to your
desired size (and fool the user by drawing your icon not to the actual size).
E.g.:
imagelist.Create( 24, 24, ILC_COLOR4, 10, 10 );
m_cList.SetImageList( &imageList, LVSIL_SMALL );
If your icon has 16x16, you make your row height 50% bigger. This seems
awkward, but it works with ease.
(Allan Gallano, 2000-11-17)
- Changing row height in
owner drawn control, Zafir Anjum, 1998-08-06, www.codeguru.com.
- Selection Highlighting of an Entire
Row, Uwe Keim, 2001-09-26, www.codeproject.com.
- Neat Stuff
to do in List Controls Using Custom Draw, Michael Dunn, 1999-11-30,
www.codeproject.com.