List Control是MFC中经常用到的控件,但是可惜该控件并不支持键盘输入、添加各种控件(Button、ComboBox...)等功能,说白了基本功能就是一个用于显示数据的表格性质控件。那么,对于键盘输入的支持以及控件的添加等功能具体如何实现,在下文中一一详述。
一、基本的使用
1.初始化风格
对于style的(报表风格、单选模式等)设置;对于ExtendedStyle(网格添加、item前添加check box等)的设置;例:
对于一个关联变量为m_Errorlist的List Control初始化:
LONG lStyle;
lStyle = GetWindowLong(m_Errorlist.m_hWnd, GWL_STYLE);//获取当前窗口style
lStyle &= ~LVS_TYPEMASK; //清除显示方式位
lStyle |= LVS_REPORT; //设置style
lStyle |= LVS_SINGLESEL;//单选模式
SetWindowLong(m_Errorlist.m_hWnd, GWL_STYLE, lStyle);//设置style
DWORD dwStyle = m_Errorlist.GetExtendedStyle();
dwStyle |= LVS_EX_FULLROWSELECT;//选中某行使整行高亮(只适用与report风格的listctrl)
dwStyle |= LVS_EX_GRIDLINES;//网格线(只适用与report风格的listctrl)
dwStyle |= LVS_EX_CHECKBOXES;//item前生成checkbox控件
m_Errorlist.SetExtendedStyle(dwStyle); //设置扩展风格
2.插入列、行
插入列:参数分别为(列位置0、列标题为Amp Enable、位置居中、列宽度、列索引号0)
m_ErrorList.InsertColumn(0, "Amp Enable", LVCFMT_CENTER, EnableListCtrlRect.Width() * 1 / 1, 0);
插入行:参数分别为(行索引0、行标题)
m_Errorlist.InsertItem(0, "caption");
3.插入子项:参数分别为(行索引号、列索引号、子项内容)
m_ListCtr.SetItemText(0,1,"content");
以上,基本功能结束。
二、Edit Control的添加(键盘输入的支持)
完成效果:双击List Control的子项,会在子项处出现编辑框;输入焦点消失后,将编辑后的内容更新到子项处。实现List Control的可编辑功能。
1.在List Control所在对话框内添加一个编辑框控件,并设为不可见;
2.对List Control添加控件的双击事件NM_DBLCLK,在触发函数内写:
void CAboutListControlDlg::OnNMDblclkList1(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast(pNMHDR);
// TODO: 在此添加控件通知处理程序代码
NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
CRect rc;
m_Row = pNMListView->iItem;//获得选中的行
m_Col = pNMListView->iSubItem;//获得选中列
if (pNMListView->iSubItem != 0) //如果选择的是子项;
{
m_ListControl.GetSubItemRect(m_Row, m_Col, LVIR_LABEL, rc);//获得子项的RECT;
m_edit.SetParent(&m_ListControl);//转换坐标为列表框中的坐标
m_edit.MoveWindow(rc);//移动Edit到RECT坐在的位置;
m_edit.SetWindowText(m_ListControl.GetItemText(m_Row, m_Col));//将该子项中的值放在Edit控件中;
m_edit.ShowWindow(SW_SHOW);//显示Edit控件;
m_edit.SetFocus();//设置Edit焦点
m_edit.ShowCaret();//显示光标
m_edit.SetSel(-1);//将光标移动到最后
}
*pResult = 0;
}
以上完成了双击显示编辑框控件,并将原子项内容更新到编辑框内;那么接下来要是实现,输入焦点消失后,编辑框的内容更新到子项内,并隐藏编辑框等待下一次双击动作。
3.给Edit Control添加KillFocus事件,并在触发函数内写:
void CAboutListControlDlg::OnEnKillfocusEdit1()
{
// TODO: 在此添加控件通知处理程序代码
CString tem;
m_edit.GetWindowText(tem); //得到用户输入的新的内容
m_ListControl.SetItemText(m_Row, m_Col, tem); //设置编辑框的新内容
m_edit.ShowWindow(SW_HIDE); //应藏编辑框
}
以上,List Control的可编辑功能完成!
三、List Control对于任意控件添加的支持(重点来了!)
以CButton类控件的添加为例!
基本思路:1.生成控件(静态/动态)2.将控件贴到List Control的指定位置 3.如有滚动条,跟随滚动条实现位置更新,且不屏闪(很重要)
1.生成控件:动态控件的生成在下一篇博客:MFC---动态生成任意数量的控件并添加消息响应 会具体介绍;
2.贴控件到指定位置处:(两种方式)
第一种:(只针对动态生成)生成时,将父窗口指针定义为ListControl且Rect为目标处的位置;
CButton *btn = new CButton();
btn->Create(str, bn_dwStyle, Rect, GetDlgItem(IDC_LIST1), IDC_Dynamic_Button0 + ButtonNum);
第二种:(动态/静态都可)控件生成后,这里
rect1同上;
btn->SetParent(&m_ListCtr);//将button设为list ctr的子窗口,即转换为list ctr的坐标!
btn->MoveWindow(rect1);//将button移动到对应位置处
3.List Control存在滚动条情况下,保证贴上去的控件位置跟随滚动条刷新,且防止屏闪
位置刷新:试了很多方法,但其实最简单实用的就是开一个Timer,在OnTimer()中对所贴上去的所有控件,调用 MoveWindow()+Invalidate()函数即可实时重绘/更新窗口;
防屏闪:为了防止重绘一直在进行,导致屏幕的闪烁,最好的办法就是在合适的条件下开启和关闭位置刷新的Timer;
展开来说就是:对ListControl添加触发函数(LVN_BEGINSCROLL),在函数体内Set上述的位置刷新Timer;也即只有在拖动滚动条时才会触发位置刷新,这是在合适的时候开启Timer;
再开一个一直在工作的Timer,在此Timer内不停获取滚动条(水平/垂直)的位置,并不断判断本次触发与上次触发时滚动条位置的变化;如果没有产生变化,则意味着滚动条的拖动停止,此时Kill位置刷新的Timer即可,这是在合适的时间关闭Timer。
附上获取滚动条位置的函数:
m_ListCtr.GetScrollPos(SB_HORZ)//水平滚动条
m_ListCtr.GetScrollPos(SB_VERT)//垂直滚动条
当然,贴上去的控件还得添加消息响应,这部分工作才算完成,见下一篇博客:MFC---动态生成任意数量的控件并添加消息响应 。
以上。