您的位置:首页 > 其它

MFC 自绘listbox , 自绘ComboBox 下拉列表框 如何设置其列表项的高度和宽度?

2013-09-03 16:48 901 查看
自绘ListBox 设置其列表项的高度和宽度可以通过重载虚函数 MeasureItem (LPMEASUREITEMSTRUCT lpMeasureItemStruct) 来实现:

void CMyComboBox::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{

// TODO:  Add your code to determine the size of specified item
lpMeasureItemStruct->itemHeight = 25;  // 设置列表项的高度为25pixel
lpMeasureItemStruct->itemWidth = 500;  // 设置列表项的宽度为500pixel , 但是这里如果你的应用程序的宽度没这么多的话,它的宽度也不会是500
}


注意事项<1>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

 

OnMeasureItem与MeasureItem的区别

重绘listbox时遇到的问题,开始在OnMeasureItem里做的操作,结果挂了。。。在MeasureItem里OK。

CSDN上达人的解释。。。清楚了。

OnMeasureItem will be called only if the control's class is created at run time, 

or it is created with the LBS_OWNERDRAWVARIABLE or CBS_OWNERDRAWVARIABLE style. 

If the control is created by the dialog editor, OnMeasureItem will not be called. 

This is because the WM_MEASUREITEM message is sent early in the creation process of the control. 

If you subclass by using DDX_Control, SubclassDlgItem, or SubclassWindow, 

the subclassing usually occurs after the creation process. 

Therefore, there is no way to handle the WM_MEASUREITEM message in the 

control's OnChildNotify function, which is the mechanism MFC uses to implement 

ON_WM_MEASUREITEM_REFLECT.

另一个的解释是OnMeasureItem是响应子控件的WM_MEASUREITEM消息的,MeasureItem是响应反射的自己发送的WM_MEASUREITEM消息的。

注意事项<2>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

 

listctrl的自绘,不是很简单,可能比CRichEditCtrl还要复杂些,遇到第一件事情是自适应改变行高,项目需要,当然也可以是固定,最终解决方案如下:

网上修改CListCtrl项高度的方法一般是扩大字体,及用图片将项高度撑大.

这两种方法虽然简单,但是效果却不是很理想.一种比较理想的方法是自画CListCtrl,不过方法相对来说比较复杂.

要修改CListCtrl的列表项高度,我们需要自己添加 MeasureItem 的消息响应函数,对应的消息是 WM_MEASUREITEM+WM_REFLECT_BASE, 而不是 WM_MEASUREITEM.在CListBox里我们可以直接在 ClassWizard 里将此消息响应添加进 class 里,但是 CListCtrl 默认是没有这个消息响应的,我们需要手动添加它(注意,这里不是 WM_MEASUREITEM. CListCtrl 仅有 WM_MEASUREITEM, 对应的函数为 OnMeasureItem).

为了响应这个消息,我们还需要给列表加上 LVS_OWNERDRAWFIXED 风格.可以在 Create 列表的时候添加,也可以在 PreCreateWindow 虚函数中添加.

添加 MeasureItem 消息响应函数,首先我们需要在类的头文件中添加:

afx_msg void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct);

来声明此消息响应函数;

然后在cpp的消息响应宏中添加:

ON_WM_MEASUREITEM_REFLECT()

最后自己建立 MeasureItem 的函数定义:

/////////////////////////////////////////////////////////////////////////////

// CListEx message handlers

void CListEx::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)

{

if( m_nItemHeight > 0 )

   lpMeasureItemStruct->itemHeight = m_nItemHeight;

}

其中 m_nItemHeight 是我在头文件中声明的一个成员变量,用于从外部修改列表项高度.

然后我们添加一个方法,便于从外部直接修改列表项高度:

//设置行高

void SetItemHeight(UINT nHeight);

然后是该方法的定义:

//设置行高

void CListEx::SetItemHeight(UINT nHeight)

{

m_nItemHeight = nHeight;

CRect rcWin;

GetWindowRect(&rcWin);

WINDOWPOS wp;

wp.hwnd = m_hWnd;

wp.cx = rcWin.Width();

wp.cy = rcWin.Height();

wp.flags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER;

SendMessage(WM_WINDOWPOSCHANGED, 0, (LPARAM)&wp);

}

这个方法的最后,使用了 SendMessage 发送 WM_WINDOWPOSCHANGED 消息让 CListCtrl 进入 MeasureItem 的消息响应函数,对列表高度进行修改.

因为我们这里使用了列表的自绘风格,因此列表项需要自己绘制.

首先在类的声明中添加 DrawItem 虚函数声明:

virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);

然后自画 CListCtrl:

void CListEx::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)

{

int    nItem = lpDrawItemStruct->itemID;

CDC*   pDC   = CDC::FromHandle(lpDrawItemStruct->hDC);

......

CRect   rcBound, rcLabel, rcIcon;

//获得列表项图标,标签,及项的区域

GetItemRect ( nItem, rcIcon, LVIR_ICON );

GetItemRect ( nItem, rcLabel, LVIR_LABEL );

GetItemRect ( nItem, rcBound, LVIR_BOUNDS );

......

}

现在这个 CListCtrl 的重载类就支持自定义列表项高度了

 

原型解释>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

MEASUREITEMSTRUCT结构体通知系统自绘控件或菜单项的尺寸.这充许系统正确的处理用户与控件的相互动作

typedef struct tagMEASUREITEMSTRUCT {   // mis

    UINT  CtlType;      // 控件类型

    UINT  CtlID;        // combo box, list box, or button 标识符

    UINT  itemID;       // menu item, variable-height list box, 菜单项,可变高的列表框

                        // or combo box identifier 或组合框的标识符

    UINT  itemWidth;    // width of menu item, in pixels 菜单项的宽,单位:象素

    UINT  itemHeight;   // height of single item in list box menu,

                        // in pixels 菜单或列表框单一项目的高,单位象素

    DWORD itemData;     // application-defined 32-bit value 应用程序定义的32位值

} MEASUREITEMSTRUCT;

CtlType:

 指定控件的类型.这个成员可以是下列的一个值:

  ODT_BUTTON    自绘按钮

  ODT_COMBOBOX  自绘组合框

  ODT_LISTBOX  自绘列表框

  ODT_LISTVIEW 自绘列表视图控件

  ODT_MENU 自绘菜单

CtlID:

 指定组合框(combo box), 列表框(list box), 或 控钮(button)的标识符.这个成员不能在菜单中使用

itemID:

 指定菜单项的标识符或组合框(combo box), 列表框(list box)的位置索引.

  列表框(list box)风格已经有LBS_OWNERDRAWVARIABLE时这个值才被指定

  组合框(combo box)风格已经有CBS_OWNERDRAWVARIABLE风格时这个值才被指定

itemWidth:

 指定宽,单位象素,一个菜单项目.在从消息返回之前,自绘菜单项的所有者必需填充这个成员.

itemHeight:

 指定高,单位象素,列表框(list box)一个个别的项或一个菜单.在从消息返回之前自绘组合框,列表框或菜单项必需填写这个参数.

itemData:

 指定与应用程序定义的菜单项相关联的32位值.做为控件,这个参数指定值是最后指定给列表框(list box)或组合框(combo box)的LB_SETITEMDATA或CB_SETITEMDATA消息中的值.如果列表框(list box)或组合框(combo box)已经使用LB_HASSTRINGS或CB_HASSTRINGS风格这个最初值是零.否则,这个值最初的值是传给列表框(list box)或组合框(combo box)

 下列消息中lparam参数的一个值:

 CB_ADDSTRING

 CB_INSERTSTRING

 LB_ADDSTRING

 LB_INSERTSTRING

备注:

 所有者窗体接收一个自绘控件的WM_MEASUREITEM消息lParam参数指向的MEASUREITEMSTRUCT结构体的指针.就在控件被创建的时候自绘控件发送这个消息到它的所有者窗体.所有者然后为控件和返回的结构体填写适当成员.

 这个结构体是共同的所有自绘控件

 如果应用程序没有填充MEASUREITEMSTRUCT适当的成员.这个控件或菜单不可能被完全的绘制

 

==================================================================

WM_MEASUREITEM消息

 

WM_MEASUREITEM

在控件或菜单被创建的时候,向自绘按钮(button),组合框(combo box),列表框(list box),

列表视图(list view)或菜单项的所有者发送WM_MEASUREITEM消息

WM_MEASUREITEM

idCtl = (UINT) wParam;                // 控件标识符

lpmis = (LPMEASUREITEMSTRUCT) lParam; // 项目大小信息

参数:

idCtl

    wParam值. lpmis参数指向MEASUREITEMSTRUCT结构体CtlID成员包含的值,

 这个值由发送到控件的WM_MEASUREITEM消息确定

 如果这个值是零.消息是由一个菜单发出.如果这个值是非零,消息是由组合框(combo box),列表框(list box)

  发出,如果这个值是非零并且lpmis指向的MEASUREITEMSTRUCT结构体itemID成员的值是(UINT)-1,

 消息是发送到组合框编辑区域.

lpmis

    lparam值.指向包含自绘控件或菜单项的尺寸的MEASUREITEMSTRUCT结构体

返回值:

 如果应用程序处理这个消息,返回的是TRUE

备注:

 就在所有者接收WM_MEASUREITEM消息的时候,所有者填充消息中lParam参数指向的MEASUREITEMSTRUCT结构体,

 这告诉系统控件的尺寸.如果一个组合框(combo box)或列表框(list box)创建时有

 LBS_OWNERDRAWVARIABLE或 CBS_OWNERDRAWVARIABLE风格,这个消息发送到所有者控件各自的项;否则,这个消息发送一次.

 在WM_INITDIALOG消息发送之前,系统为在创建时有OWNERDRAWFIXED风格的列表框和组合框的所有者窗体

 发送WM_MEASUREITEM消息.在所有者收到这个消息的时候,系统还没有决定控件使用字体的宽度和高度尺寸.

 将在应用程序或库中调用主要的函数计算需要的值

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: