编写一个类似VC6添加文件,单击则动态显示一个Edit编辑框与一个Button。效果如下图:
1.新建一个类(如CMyListBox),继承自CListBox
2.头文件中定义Edit与CButton变量
CEdit m_edit;
CButton m_btn;
3.定义一个初始化函数,供对话框调用。
首先在.cpp中定义2个ID
#define MY_EDIT 10001
#define MY_BTN 10002
void CMyListBox::Init() { m_edit.Create(WS_BORDER | WS_CHILD | ES_AUTOHSCROLL,CRect(0,0,10,10),this,MY_EDIT); // 设置字体 // 方法一: HFONT hf = reinterpret_cast<HFONT>(::GetStockObject(DEFAULT_GUI_FONT)); m_edit.SetFont(CFont::FromHandle(hf)); // 方法二: //HFONT hf = CreateFont(22,0,0,0,FW_DONTCARE,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_OUTLINE_PRECIS, // CLIP_DEFAULT_PRECIS,CLEARTYPE_QUALITY,FIXED_PITCH,_T("Courier New")); //if(hf != NULL) //{ // ::SendMessage(GetDlgItem(MY_EDIT)->m_hWnd,WM_SETFONT,reinterpret_cast<WPARAM>(hf),TRUE); //} m_btn.Create(_T("..."),WS_CHILD,CRect(0,0,10,10),this,MY_BTN); m_menu.LoadMenu(IDR_MY_MENU); }
4.重载OnLButtonDown 与 OnLbnSelchange 函数
(1)OnLbutton函数要做的是:
获取数据个数(GetCount);
判断左键按下是否在有效的行(GetItemRect); 不在,SetCurSel(-1);调用 更新显示函数(UpdateDisplay)。
void CMyListBox::OnLButtonDown(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 // 获取个数 int nCount = GetCount(); int i = 0; CRect rc; for(i=0; i<nCount; ++i) { GetItemRect(i,rc); if(rc.PtInRect(point)) { break; } } if(i >= nCount) // 未找到,不在 { SetCurSel(-1); UpdateDisplay(); // 更新位置函数 } CListBox::OnLButtonDown(nFlags, point); }
(2)OnLbnSelchange函数:
判断edit与button是否可见,可见则隐藏。更新显示(UpdateDisplay)
void CMyListBox::OnLbnSelchange() { // TODO: 在此添加控件通知处理程序代码 if(m_edit.IsWindowVisible()) { m_edit.ShowWindow(SW_HIDE); } if(m_btn.IsWindowVisible()) { m_btn.ShowWindow(SW_HIDE); } UpdateDisplay(); }
更新显示函数(UpdateDisplay):
获取当前所选项(GetCurSel);为LB_ERR则让edit与button隐藏
获取按下位置的当前矩形大小GetItemRect;
edit与button根据获取到的矩形区域,设置rect,调用MoveWindow;
获取当前行的text,更新到edit控件上显示。
edit设置焦点。
// 更新显示函数 void CMyListBox::UpdateDisplay() { int index = GetCurSel(); if(index == LB_ERR) { if(m_edit.IsWindowVisible()) { m_edit.ShowWindow(SW_HIDE); } if(m_btn.IsWindowVisible()) { m_btn.ShowWindow(SW_HIDE); } return; } CRect rc; GetItemRect(index,rc); // 获取在第几行 CRect rcEdit(rc.left,rc.top,rc.right-20,rc.bottom+5); m_edit.MoveWindow(rcEdit); CRect rcBtn(rc.right-20,rc.top,rc.right,rc.bottom+5); m_btn.MoveWindow(rcBtn); // 更新Edit显示内容 CString strContent; GetText(index,strContent); m_edit.SetWindowText(strContent); m_edit.SetSel(0,-1); // 全选 if(!m_edit.IsWindowVisible()) { m_edit.ShowWindow(SW_SHOW); } if(!m_btn.IsWindowVisible()) { m_btn.ShowWindow(SW_SHOW); } m_edit.SetFocus(); }
动态按钮(MY_BTN):
自定义消息与响应函数
afx_msg void OnMyBtnClick();
ON_BN_CLICKED(MY_BTN,OnMyBtnClick)
响应为 弹出一个选择文件夹对话框,点击确定后,更新CListBox中内容。
void CMyListBox::OnMyBtnClick() { CString strPath; TCHAR szDir[MAX_PATH]; BROWSEINFO bi; bi.hwndOwner = this->m_hWnd; bi.pidlRoot = NULL; bi.pszDisplayName = szDir; bi.lpszTitle = _T("请选择目录"); bi.ulFlags = BIF_STATUSTEXT | BIF_USENEWUI | BIF_RETURNONLYFSDIRS; bi.lpfn = NULL; bi.lParam = 0; bi.iImage = 0; ITEMIDLIST *pidl = SHBrowseForFolder(&bi); if(pidl == NULL) { return; } if(!SHGetPathFromIDList(pidl,szDir)) { return; } else { strPath = szDir; UpdateContent(strPath); // 更新CListBox数据 } }
更新CListBox数据UpdateContent:
删除默认行,重新插入数据到当前行,末尾加上默认行,让edit与button隐藏
// 更新ListBox内容 void CMyListBox::UpdateContent(const CString str) { int index = GetCurSel(); DeleteString(index); AddString(str); InsertFlagString(); SetCurSel(-1); SetFocus(); if(m_edit.IsWindowVisible()) { m_edit.ShowWindow(SW_HIDE); } if(m_btn.IsWindowVisible()) { m_btn.ShowWindow(SW_HIDE); } }
4. 右键菜单:删除
资源中添加菜单,类中定义一个CMenu变量。初始化时LoadMenu。
右键按下时响应函数OnRButtonDown:
void CMyListBox::OnRButtonDown(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 CRect rc; CMenu *popMenu = m_menu.GetSubMenu(0); int nCount = GetCount(); int i = 0; for(; i<nCount; ++i) { GetItemRect(i,rc); if(rc.PtInRect(point)) { if(i == nCount-1) { SetCurSel(-1); popMenu->EnableMenuItem(ID_DELETE,MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); } else { SetCurSel(i); popMenu->EnableMenuItem(ID_DELETE,MF_BYCOMMAND | MF_ENABLED); break; } } } ClientToScreen(&point); popMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON,point.x,point.y,this); CListBox::OnRButtonDown(nFlags, point); }
删除(ID_DELETE)添加处理函数OnDelete:
void CMyListBox::OnDelete() { // TODO: 在此添加命令处理程序代码 int index = GetCurSel(); DeleteString(index); }
此时,初步完成以上效果,当点击...按钮弹出 "选择文件对话框",点OK后,更新显示在ListBox中。唯一不足是,edit数据内容只能通过...按钮点确定后才更改,直接点击修改不起作用。可能需要窗口子类化。有时间再修改。