在实现随机生成四则运算的个人项目中,目前已经完成基本功能,想要把程序变成一个Windows界面的程序。原本以为学习过MFC,应该很快就能完成。但是由于以前用的都是VC6.0,这次用了VS2010,稍微有点不适应,而且也有一段时间没用,悲催地发现自己已经很不熟练了(╮(╯▽╰)╭基本上自己以前写的MFC应用程序都是看网上傻瓜教程,扯远了~~~)。经过分析发现,用MFC实现显示四则运算表达式然后接受用户输入答案,单纯地用List Control好像不能实现,所以又在网上搜索了实现可编辑List-Control的教程,自己跟着实现了一遍。
首先,创建的是基于对话框的MFC应用程序,对话框为FourArithOperDlg,在FourArithOperDlg.h中添加如下变量和函数:
1 int e_Item;//刚编辑的行 2 int e_SubItem;//刚编辑的列 3 CEdit m_Edit;//生成单元编辑框 4 bool haveeditcreate;//标志编辑框已经被创建 5 void createEdit(NM_LISTVIEW *pEditCtrl, CEdit *createdit, int &Item, int &SubItem, bool &havecreat);//创建单元格编辑框函数 6 void distroyEdit(CListCtrl *list, CEdit* distroyedit, int &Item, int &SubItem);//销毁单元格编辑框对象
在对话框的初始函数中添加初始化代码如下:这里的列表框第一行显示表达式,第二行显示答案。
1 CRect rect; 2 m_expression.GetClientRect(&rect); 3 m_expression.SetExtendedStyle(m_expression.GetExtendedStyle() | LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES); 4 m_expression.InsertColumn(0,_T("运算表达式"), LVCFMT_CENTER, rect.Width()/2,0); 5 m_expression.InsertColumn(1,_T("结果"), LVCFMT_CENTER, rect.Width()/2,1); 6 m_expression.InsertItem(0,_T("1+1")); 7 m_expression.SetItemText(0,1,_T("2")); 8 haveeditcreate = false;
为列表框添加单击响应函数,NM_CLICK,这里只是让第二列,也就是显示答案的那一列单击产生编辑框。
1 NM_LISTVIEW * pEditCtrl = (NM_LISTVIEW *)pNMHDR; 2 printf("行:%d,列:%d\n",pEditCtrl->iItem,pEditCtrl->iSubItem); 3 if (pEditCtrl->iItem == -1)//点击到非工作区 4 { 5 if (haveeditcreate == true)//如果之前创建了编辑框就销毁掉 6 { 7 distroyEdit(&m_expression,&m_Edit,e_Item,e_SubItem);//销毁单元格编辑对象 8 haveeditcreate = false; 9 } 10 } 11 else if(pEditCtrl->iSubItem == 1)//如果选择第二列 12 { 13 if (haveeditcreate == true) 14 { 15 if (!(e_Item == pEditCtrl->iItem && e_SubItem == pEditCtrl->iSubItem))//如果点中的单元格不是之前创建的 16 { 17 distroyEdit(&m_expression,&m_Edit,e_Item,e_SubItem); 18 haveeditcreate = false; 19 createEdit(pEditCtrl,&m_Edit,e_Item,e_SubItem,haveeditcreate); 20 } 21 else //点中的单元格是之前创建的 22 { 23 m_Edit.SetFocus();//设置为焦点 24 } 25 } 26 else 27 { 28 e_Item = pEditCtrl->iItem; 29 e_SubItem = pEditCtrl->iSubItem; 30 createEdit(pEditCtrl,&m_Edit,e_Item,e_SubItem,haveeditcreate);//创建编辑框 31 } 32 }
接下来就是创建与销毁单元格编辑框的实现了。
1 void CFourArithOperDlg::distroyEdit(CListCtrl *list,CEdit* distroyedit, int &Item, int &SubItem) 2 { 3 CString meditdata; 4 distroyedit->GetWindowTextW(meditdata); 5 list->SetItemText(Item, SubItem, meditdata);//获得相应单元格字符 6 distroyedit->DestroyWindow();//销毁对象,有创建就要有销毁,不然会报错 7 }
1 void CFourArithOperDlg::createEdit(NM_LISTVIEW *pEditCtrl, CEdit *createdit, int &Item, int &SubItem, bool &havecreat) 2 { 3 Item = pEditCtrl->iItem;//将点中的单元格的行赋值给“刚编辑过的行”以便后期处理 4 SubItem = pEditCtrl->iSubItem;//将点中的单元格的行赋值给“刚编辑过的行”以便后期处理 5 createdit->Create(ES_AUTOHSCROLL | WS_CHILD | ES_LEFT | ES_WANTRETURN, 6 CRect(0, 0, 0, 0), this, IDC_EDIT_CREATEID);//创建编辑框对象,IDC_EDIT_CREATEID为控件ID号3000,在Resource.h中定义 7 havecreat = true; 8 createdit->SetFont(this->GetFont(), FALSE);//设置字体,不设置这里的话上面的字会很突兀的感觉 9 createdit->SetParent(&m_expression);//将list control设置为父窗口,生成的Edit才能正确定位,这个也很重要 10 CRect EditRect; 11 m_expression.GetSubItemRect(e_Item, e_SubItem, LVIR_LABEL, EditRect);//获取单元格的空间位置信息 12 EditRect.SetRect(EditRect.left+1, EditRect.top+1, EditRect.left + m_expression.GetColumnWidth(e_SubItem)-1, EditRect.bottom-1);//+1和-1可以让编辑框不至于挡住列表框中的网格线 13 CString strItem = m_expression.GetItemText(e_Item, e_SubItem);//获得相应单元格字符 14 createdit->SetWindowText(strItem);//将单元格字符显示在编辑框上 15 createdit->MoveWindow(&EditRect);//将编辑框位置放在相应单元格上 16 createdit->ShowWindow(SW_SHOW);//显示编辑框在单元格上面 17 createdit->SetFocus();//设置为焦点 18 createdit->SetSel(-1);//设置光标在文本框文字的最后 19 }
然后,解决单元格编辑框中回车键的处理,在教程中说可以重载对话框类的OnOK函数来避免。所以在对话框类中添加声明
1 afx_msg void OnOk();
在对话框cpp文件中函数内为空。
1 void CFourArithOperDlg::OnOk() 2 {}
但是此时,在编辑框中修改数据,然后点击其他的单元格,编辑框还停留在上一个单元格中,所以在对话框类声明中添加动态生成编辑框失去焦点响应函数
1 afx_msg void OnKillFocusEdit();
然后在对话框类实现地消息映射描述中添加
1 ON_EN_KILLFOCUS(IDC_EDIT_CREATEID,&CFourArithOperDlg::OnKillFocusEdit)
处理函数:
1 void CFourArithOperDlg::OnKillFocusEdit() 2 { 3 if (haveeditcreate == true) 4 { 5 distroyEdit(&m_expression,&m_Edit,e_Item,e_SubItem); 6 haveeditcreate = false; 7 } 8 }
现在,基本完成了对话框的第二列可以编辑的功能了,效果图:
通过这个可编辑列表框的实现教程,熟悉了在VS中创建简单的MFC应用程序的过程。