在我们进行mfc 编程时,我们需要用到列表框显示各层或各物体的参数设置,同时也希望能编辑其参数。我以前在网上查找,用了CComboListCtrl,这需要3个cpp 和 h 文件,用起来还不容易。
最近看到一个文章 https://blog.csdn.net/qingyang8513/article/details/50986455 ,这个直接用 listctrl 和 一个Edit 控件,很简单。所以我也测试一下,并记录在此。
运行效果如下,点击一处列表框里内容即可编辑,但我剪辑图时剪辑不到编辑状态。
我的运行环境是vc2010,下面开始讲解过程:
重点内容:
1)List Control控件NM_DCLICK消息响应事件;
2)Edit Control的KillFocus消息响应;
3)Edit Control的动态显示及隐藏;
4)List Control获取指定行和列的编号,并获取指定行和列的内容及修改赋值。
操作:
1、创建基于对话框的MFC应用程序,删除原有的静态文本;
2、添加一个List Control控件和一个Edit Control控件,并分别关联控制变量m_ListTem和m_EditTest(List Control控件适当调整大小,Edit Control大小不用调整);
3、初始化对话框函数OnInitDialog中实现List Control控件和Edit Control控件的初始化, InitList(); UpdateList();
代码如下:
BOOL CListCtrlTestDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// TODO: Add extra initialization here
InitList();
UpdateList();
return TRUE; // return TRUE unless you set the focus to a control
}
void CListCtrlTestDlg::InitList(void)
{
Clayer layer={"zhang",1.3,15.6,88};
m_layer.push_back(layer);
Clayer layer1={"Li",22.3,25.6,288};
m_layer.push_back(layer1);
Clayer layer2={"Wang",32.33,35.6,388};
m_layer.push_back(layer2);
m_EditTest.ShowWindow(SW_HIDE);
CRect rect;
m_ListTem.GetClientRect(&rect);
int iLength = rect.Width();
m_ListTem.SetExtendedStyle(m_ListTem.GetExtendedStyle() | LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);
m_ListTem.InsertColumn(0, _T("编号"), LVCFMT_CENTER, 40);
m_ListTem.InsertColumn(1, _T("名字"), LVCFMT_CENTER, 80);
m_ListTem.InsertColumn(2, _T("x"), LVCFMT_CENTER, (iLength - 120)/3);
m_ListTem.InsertColumn(3, _T("y"), LVCFMT_CENTER, (iLength - 120)/3);
m_ListTem.InsertColumn(4, _T("旋转角度"), LVCFMT_CENTER, (iLength - 120)/3);
}
void CListCtrlTestDlg::UpdateList(void)
{
CString index,x,y,z,name,count,rotate,blocks;
while(m_ListTem.GetItemCount()>0)
m_ListTem.DeleteItem(0);
for(int i=0;i<m_layer.size();i++)
{
index.Format("%d",i);
Clayer& layer=m_layer[i];
name=layer.name;
x.Format("%.2f",layer.x);
y.Format("%.2f",layer.y);
count.Format("%d",layer.count);
m_ListTem.InsertItem(i,index);
m_ListTem.SetItemText(i,1,name);
m_ListTem.SetItemText(i,2,x);
m_ListTem.SetItemText(i,3,y);
m_ListTem.SetItemText(i,4,count);
}
}
在h 文件中定义层参数结构,并定义层参数向量m_layer.
typedef struct {CString name;float x;float y;int count;} Clayer;
std::vector<Clayer> m_layer;
有上面,上面代码才不报错。这里完成了初始显示,应该可以得到开头的效果,但不能编辑。
动态编辑的核心
4、对话框头文件中添加int型变量m_Row和m_Col,用于保存双击时选中的行和列号,并初始化为-1(未选中状态);
5、为List Control控件添加NM_DBLCLK消息响应,并添加代码如下:
void CListCtrlTestDlg::OnDblclkList2(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
// TODO: Add your control notification handler code here
CRect rc;
CString strTemp;
NM_LISTVIEW *pNMListView = (NM_LISTVIEW *)pNMHDR;
m_Row = pNMListView->iItem;
m_Col = pNMListView->iSubItem;
if (pNMListView->iItem == -1) //选择空白处
return;
if (m_Col != 0) // 选择子项
{
m_ListTem.GetSubItemRect(m_Row, m_Col, LVIR_LABEL, rc);
m_EditTest.SetParent(&m_ListTem);
m_EditTest.MoveWindow(rc);
m_EditTest.SetWindowText(m_ListTem.GetItemText(m_Row, m_Col));
m_EditTest.ShowWindow(SW_SHOW);
m_EditTest.SetFocus();//设置Edit焦点
m_EditTest.ShowCaret();//显示光标
m_EditTest.SetSel(0, -1);//全选
}
*pResult = 0;
}
6、为Edit Control控件添加EN_KILLFOCUS消息响应,并添加代码如下:
void CListCtrlTestDlg::OnKillfocusEdit1()
{
// TODO: Add your control notification handler code here
CString str;
m_EditTest.GetWindowText(str);
m_ListTem.SetItemText(m_Row, m_Col, str);
//这里其实应该保存编辑结果,简化了,实际程序要有改变参数
m_EditTest.ShowWindow(SW_HIDE);
}
现在可以编译运行并测试程序了,应该就是我们开头的结果。
改进
输入完数据后,一般希望回车,就生效,可实际情况是要离开才生效,有点操作不方便。
编辑框怎么相应回车呢?
类精灵CListCtrlTestDlg里转到 Virtual function,点击添加 PreTranslateMessage
编辑PreTranslateMessage函数如下:
BOOL CListCtrlTestDlg::PreTranslateMessage(MSG* pMsg)
{
if (WM_KEYDOWN ==pMsg->message && VK_RETURN == pMsg->wParam)
{
if (m_EditTest.IsWindowVisible())
{
m_EditTest.ShowWindow(SW_HIDE);
return TRUE;
}
}
return CDialogEx::PreTranslateMessage(pMsg);
}
这段代码的含义是:在按下回车键时, 如果编辑框是可见的,就让编辑框不显示。编辑框不显示就触发EN_KILLFOCUS消息。达到回车就保存的目的。