65.9K
CodeProject 正在变化。 阅读更多。
Home

在所有者绘制控件中更改行高

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.89/5 (24投票s)

2001 年 9 月 27 日

CPOL

4分钟阅读

viewsIcon

368635

downloadIcon

6799

在所有者绘制的列表视图控件中更改行高

目录

历史

2001-10-10 插入示例 "multiline.zip",来自 Danielle

2001-09-27 创建文章

前言

本文是 Codeguru 上文章 "更改拥有者绘制控件中的行高" 的一个近乎改编。在尽量保留原有内容的同时,我尽可能地对其进行了增强。我还包含了对文章评论的总结。

引言

当您更改 列表视图 控件的字体时,控件或其父窗口没有机会重新指定行高。没有 WM_MEASUREITEM 消息会被发送到控件的父窗口。最终结果是,当更改控件的字体时,行高将不再有效。

这里有一个解决方法,可以强制生成 WM_MEASUREITEM 消息

分步指南

以下步骤中的代码使用了 MFC 及其类 CListCtrl

步骤 1:为 WM_SETFONT 添加处理程序

WM_MEASUREITEM 消息在控件创建时发送。幸运的是,每当控件调整大小时都会发送此消息。由于我们希望在字体更改时调整行高,那么在 WM_SETFONT 处理程序中执行此操作再合适不过了。在 OnSetFont() 中,我们欺骗 Windows,使其认为控件的窗口大小已更改。

我们通过向控件发送 WM_WINDOWPOSCHANGED 消息来实现这一点,然后该消息由控件的默认窗口过程处理。请注意,我们没有指定 SWP_NOSIZE 标志,并且我们将 WINDOWPOS 结构中的宽度和高度字段设置为等于现有尺寸。

在头文件中

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

在 CPP 文件中

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;
}

步骤 2:为 WM_MEASUREITEM 添加处理程序

由于我们希望我们的 CListCtrl 派生类是模块化的,因此我们将在该类中处理 WM_MEASUREITEM 消息。但是,此消息发送到父窗口,因此我们使用消息反射。同样,类向导的帮助不大。我们必须手动将条目添加到消息映射中并更新头文件。有关此内容,请参见第一步中的代码片段。

void CMyListCtrl::MeasureItem( LPMEASUREITEMSTRUCT lpMeasureItemStruct )
{
    LOGFONT lf;
    GetFont()->GetLogFont( &lf );
    
    if ( lf.lfHeight < 0 )
        lpMeasureItemStruct->itemHeight = -lf.lfHeight; 
    else
        lpMeasureItemStruct->itemHeight = lf.lfHeight; 
}

结论

到目前为止,这些步骤都改编自原始文章。接下来是原始文章中最有趣的评论的摘要。评论包括对先前步骤的修复和更正。由于我希望保留文章的原样,因此我决定*不*在上面的代码片段中包含建议的修复。是否使用它们由您决定。另一个原因是,我不知道所有建议的修复是否正确。请在此处留下评论,以便我删除/调整任何错误。

读者评论

MeasureItem() 例程的正确实现

问题/解决方案:
MeasureItem() 例程中为 CListCtrl 派生对象设置行高时,不应使用 LOGFONT 结构体的 lfHeight 成员。此值是逻辑磅值,不是物理像素值。对于不同的屏幕分辨率和更大的字体值,行高仍然会不正确。以下代码显示了一个实现 MeasureItem() 例程的示例,该例程应适用于所有这些情况,并且产生的行高与默认实现完全相同。

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 )

我没有收到 WM_SETFONTWM_MEASUREITEM 消息

问题:
我没有收到 WM_SETFONTWM_MEASUREITEM 消息。

(Damian Williams, 1999-10-18)

解决方案

  1. 将列表控件的样式修改为“拥有者绘制固定”(LVS_OWNERDRAWFIXED)。
  2. 重载 CListCtrlEx::DrawItem()
  3. WM_MEASUREITEM 消息将被发送到列表控件的父窗口。

(Chung Hyun, Lee, 2000-05-25)

解决方案 2:
类向导不会显示 =WM_MEASUREITEM 反射消息。如果您使用类向导获取 WM_MEASUREITEMS,它只能由列表视图控件以外的类处理,即父窗口。这是不令人满意的。要获取反射消息,您必须在 .CPP 文件中的消息映射中添加以下内容

ON_WM_MEASUREITEM_REFLECT()

然后,您必须在头文件消息映射中添加以下内容

afx_msg void MeasureItem( LPMEASUREITEMSTRUCT lpMeasureItemStruct );

然后,在 .CPP 文件中添加以下函数

void CMyListCtrl::MeasureItem ( LPMEASUREITEMSTRUCT lpMeasureItemStruct )
{
    // this should happen when the control is created.
    AfxMessageBox("You just received a WM_MEASUREITEM message");
}

(Dominic Gamble, 2000-01-13)

解决方案 3:
首先,您必须使用 LVS_OWNERDRAWFIXED 样式创建列表视图控件。然后,使用 CWnd::MoveWindow()CWnd::SetWindowPos() 函数更改控件的大小。

这两种情况都适用:手工创建的控件(通过调用 CListCtrl::Create())和模板创建的控件(使用资源编辑器)。

(Gon (Jung-gon, Kim), 2000-08-09)

更改行高而不使用 LVS_OWNERDRAWFIXED

问题/解决方案
您可以通过将图像列表图标的大小设置为所需大小来轻松更改行高(并通过绘制非实际大小的图标来欺骗用户)。例如:

imagelist.Create( 24, 24, ILC_COLOR4, 10, 10 ); 
m_cList.SetImageList( &imageList, LVSIL_SMALL ); 

如果您的图标大小为 16x16,则将行高增加 50%。这看起来有点笨拙,但它很容易奏效。

(Allan Gallano, 2000-11-17)

另请参阅/参考文献

  1. 更改拥有者绘制控件中的行高, Zafir Anjum, 1998-08-06, www.codeguru.com。
  2. 选择高亮显示整行, Uwe Keim, 2001-09-26, www.codeproject.com。
  3. 使用自定义绘制在列表控件中进行的整洁操作, Michael Dunn, 1999-11-30, www.codeproject.com。
© . All rights reserved.