List Control 可编辑任意item文本,设置行高
邵盛松 2010年11月22日星期一
下载地址:http://download.csdn.net/source/2852621
本文使用Owner Draw实现List Control的重绘
一 可编辑任意item文本
1)List Control 列表控件部分
将List Control的Owner Draw Fixed的属性设置为True.编译器的说明是指定所有者窗口将在报表视图中绘制项。也可以使用ModifyStyle函数设置。
必须重载DrawItem函数,在这个函数中编写自己的自绘代码。否则插入数据会弹出一个调试框。
添加一个继承自CListCtrl的类,类名是COrangeListCtrl
在编译器的属性窗口的重写面板,添加DrawItem函数,编译器会自动添加代码,
void COrangeListCtrl::DrawItem(LPDRAWITEMSTRUCT /*lpDrawItemStruct*/)
{
// TODO: 添加您的代码以绘制指定项
}
需要将参数的注释符号去掉。启用参数。
在编写之前需要了解一些结构体,因为这个Demo是在Unicode编码下调试的,所以会看到有的结构体名称后面带个W。
LPDRAWITEMSTRUCT包含项的信息。
LVITEM用于定义项结构。
LPDRAWITEMSTRUCT类型的结构
/*
* DRAWITEMSTRUCT for ownerdraw
*/
typedef struct tagDRAWITEMSTRUCT {
UINT CtlType;
UINT CtlID;
UINT itemID;
UINT itemAction;
UINT itemState;
HWND hwndItem;
HDC hDC;
RECT rcItem;
ULONG_PTR itemData;
} DRAWITEMSTRUCT, NEAR *PDRAWITEMSTRUCT, FAR *LPDRAWITEMSTRUCT;
LVITEM类型的结构
typedef struct tagLVITEMW
{
UINT mask;
int iItem;
int iSubItem;
UINT state;
UINT stateMask;
LPWSTR pszText;
int cchTextMax;
int iImage;
LPARAM lParam;
#if (_WIN32_IE >= 0x0300)
int iIndent;
#endif
#if (_WIN32_WINNT >= 0x501)
int iGroupId;
UINT cColumns; // tile view columns
PUINT puColumns;
#endif
} LVITEMW, *LPLVITEMW;
重绘部分代码
void COrangeListCtrl::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
// TODO: 添加您的代码以绘制指定项
CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
LVITEM lvi = {0};
lvi.mask = LVIF_STATE;
lvi.stateMask = LVIS_FOCUSED | LVIS_SELECTED ;
lvi.iItem = lpDrawItemStruct->itemID;
BOOL bGet = GetItem(&lvi);
BOOL bHighlight =((lvi.state & LVIS_DROPHILITED)||((lvi.state & LVIS_SELECTED) && ((GetFocus() == this)|| (GetStyle() & LVS_SHOWSELALWAYS))));
CRect rcBack = lpDrawItemStruct->rcItem;
if( bHighlight ) //高亮显示
{
pDC->SetTextColor(::GetSysColor(COLOR_HIGHLIGHTTEXT));
pDC->SetBkColor(::GetSysColor(COLOR_HIGHLIGHT));
pDC->FillRect(rcBack, &CBrush(::GetSysColor(COLOR_HIGHLIGHT)));
}
else
{
pDC->SetTextColor(::GetSysColor(COLOR_WINDOWTEXT));
pDC->FillRect(rcBack, &CBrush(::GetSysColor(COLOR_WINDOW)));
}
//绘制文本
CString strText=L"";
CRect rcItem;
if (lpDrawItemStruct->itemAction & ODA_DRAWENTIRE)
{
for (int i = 0; i < GetHeaderCtrl()-> GetItemCount();i++)
{
if ( !GetSubItemRect(lpDrawItemStruct->itemID, i, LVIR_LABEL, rcItem ))
continue;
strText = GetItemText( lpDrawItemStruct->itemID, i );
pDC->DrawText(strText,strText.GetLength(), &rcItem, DT_LEFT|DT_VCENTER|DT_SINGLELINE|DT_BOTTOM);
}
}
}
子类化之前设置List Control为Owner Draw风格,这样可以不用在资源视图设置Owner Draw Fixed的属性。
void COrangeListCtrl::PreSubclassWindow()
{
// TODO: 在此添加专用代码和/或调用基类
ModifyStyle(0,LVS_OWNERDRAWFIXED);
CListCtrl::PreSubclassWindow();
}
在单击Item时出现编辑框, m_Edit_ctlItem是自定义的编辑框对象
void COrangeListCtrl::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CListCtrl::OnLButtonDown(nFlags, point);
CRect rcCtrl;
LVHITTESTINFO lvhti;
lvhti.pt = point;
m_nItem =SubItemHitTest(&lvhti);
if (m_nItem == -1) return;
m_nSubItem = lvhti.iSubItem;
GetSubItemRect(m_nItem,m_nSubItem,LVIR_LABEL,rcCtrl);
if (m_Edit_ctlItem.m_hWnd == NULL)
{
m_Edit_ctlItem.Create(ES_AUTOHSCROLL|WS_CHILD|ES_LEFT|ES_WANTRETURN|WS_BORDER,CRect(0,0,0,0),this,99);
m_Edit_ctlItem.ShowWindow(SW_HIDE);
m_FontItem.CreateStockObject(DEFAULT_GUI_FONT);
m_Edit_ctlItem.SetFont(&m_FontItem);
m_FontItem.DeleteObject();
}
CString strItem=GetItemText(m_nItem,m_nSubItem);
m_Edit_ctlItem.MoveWindow(&rcCtrl);
m_Edit_ctlItem.ShowWindow(SW_SHOW);
m_Edit_ctlItem.SetWindowText(strItem);
m_Edit_ctlItem.SetFocus();
m_Edit_ctlItem.SetSel(-1);
}
添加自定义消息映射函数OnEndEdit表示完成编辑,将编辑框中的数据赋值给点击时所在的项。
消息映射函数声明
afx_msg LRESULT OnEndEdit(WPARAM wParam,LPARAM lParam);
消息映射
ON_MESSAGE(ORANGE_LVN_ENDEDIT, OnEndEdit)
消息映射函数实现部分
LRESULT COrangeListCtrl::OnEndEdit(WPARAM wParam,LPARAM lParam)
{
CString strText;
m_Edit_ctlItem.GetWindowText(strText);
SetItemText(m_nItem,m_nSubItem,strText);
m_Edit_ctlItem.ShowWindow(SW_HIDE);
return 0;
}
2)Edit Box 编辑框部分
添加一个继承自 CEdit的类,类名是COrangeEdit
当编辑框失去焦点时发送完成编辑消息
void COrangeEdit::OnKillFocus(CWnd* pNewWnd)
{
CEdit::OnKillFocus(pNewWnd);
// TODO: 在此处添加消息处理程序代码
CWnd* pParent = this->GetParent();
::SendMessage(pParent->GetSafeHwnd(),ORANGE_LVN_ENDEDIT,0,0);
}
二 设置行高
1)重写MeasureItem函数
void COrangeListCtrl::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
if (m_nRowHeight>0)
{
lpMeasureItemStruct->itemHeight = m_nRowHeight;
}
}
注意不是OnMeasureItem函数,MeasureItem需要手动添加
2)SetRowHeigt设置行高的接口函数
void COrangeListCtrl::SetRowHeigt(int nHeight)
{
m_nRowHeight = 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);
}
以上程序在 VC++2005 Unicode字符集下调试通过