论坛中搜索一下,你会发现不少类似的提问:我如何编辑list control的条目?如何直接编辑list control...等等;list control可用来做数据库表的视图,十分有用.
但报表风格的list control只能编辑第一列,其余的该死的微软没为vc做到.它怕VB卖不出.于是C++程序员只好DIY.主要思想是在list control中动态创建一个控件,动态移动该控件到相应位置.这些方法早有人讨论过了,本文也是基于如上思想的,但注重于可扩充性与使用的方便.
List control 这头主要是重载OnLButtonDown方法,计算出被点中的条目.这里重要的函数是SubItemHitTest和GetSubItemRect,看msdn上有相关说明. 用户点中后,就要负责显示控件了:如果之前选中了其他,就要验证之前的改动是否成功.不成功就要回到原来的地方,成功就应用修改并移到新位置.看代码:
static const UINT IDCHAILD=3000;
void CValidateList::OnLButtonDown(UINT nFlags, CPoint point)
{
CListCtrl::OnLButtonDown(nFlags, point);
LVHITTESTINFO hi;
hi.pt = point;
if(SubItemHitTest(&hi) != -1 )//没有点中条目就不管
{if(m_col==-1||//-1 还没被选过
true==(m_col+m_validate)->Validate (m_row))
{
m_row = hi.iItem, m_col= hi.iSubItem;//m_row,m_col成
//员分别跟踪选中的行列
}
((m_col+m_validate))->Move (_GetRect(),m_row);
}
}
WinBlast* CValidateList::SetValidate( WinBlast*in)//设置验证的
//控件群,in对应第一列,in+1第二列……
{
WinBlast*ret=m_validate;
m_validate=in;
int counts=GetHeaderCtrl()->GetItemCount();;
RECT rect;
memset(&rect,0,sizeof(rect));
for(int i=0;i<counts;++i)
(in+i)->Create (this,rect,IDCHAILD+i,i);
m_col=-1;//没有被选中的
return ret;
}
RECT CValidateList::_GetRect()//内部使用,得到相应显示位置
{
CRect ret;
GetSubItemRect(m_row,m_col,LVIR_BOUNDS,ret);
return ret;
}
void CValidateList::NoSelect()//置未选中状态
{
m_col=-1;//没有被选中的
}
看到了WinBlast*ret=m_validate吧.WinBlast是用来修改和验证数据的控件看它的实现:
class WinBlast
{
int m_col;//跟踪列,为什么要这个?因为你可以让一种控件对
//不同列用不同的验证策略
CWnd* m_win;//你的控件窗口
CListCtrl *m_parent;//用它获得文本
public:
WinBlast(){m_win=NULL;}
~WinBlast(){m_win->DestroyWindow();delete m_win;}
virtual bool Create( CWnd* pParentWnd,
const RECT& rect, UINT nID,
int col)
{
m_col=col;m_parent=(CListCtrl *)pParentWnd;
m_win=new CEdit;
return ((CEdit*)m_win)->
Create(ES_NOHIDESEL,rect,pParentWnd,nID);
}
void Move(const RECT &rect,int row)//最重要的函数但前面
//两个动作是必作的,SetText为虚,你在那做你喜欢的
{
m_win->ShowWindow(SW_SHOW);
m_win->MoveWindow(&rect);
SetText(row);
}
virtual bool Validate(int row)//验证,虚函数.这里永远返回true
{
m_win->ShowWindow(SW_HIDE);
CString set;
m_win->GetWindowText(set);
m_parent->SetItemText(row,m_col,set);
return true;
}
virtual void SetText(int row)
{
m_win->SetWindowText(m_parent->GetItemText(row,m_col));
((CEdit*)m_win)->SetSel (0,-1);
}
};
实际使用通常是这样的:
WinBlast*p=new WinBlast[sizeof(col)/sizeof(col[0])];//col是
//列名字符数组,sizeof(col)/sizeof(col[0])计算列数
m_test.SetValidate (p);//m_test是CValidateList类
你可以继承WinBlast,重载Create建立一个下拉框,加入你喜爱的验证方法.
注意我的设计漏洞:CValidateList应接收WinBlast**,而不是WinBlast*-----不理解这个漏洞其实也不要紧:但要记住,不改正的话你的WinBlast后继类就不能加数据成员了.
第一次发表文章,不足之处尽管批评.想要完整源码请告知Email