在VC++6.0下構建可直接編輯的列表控件類

在VC++6.0下構建可直接編輯的列表控件類
 

劉  婭

摘要 MFC中的CListCtrl類用於封裝列表控件的各種操作,但CListCtrl類不支持直接編輯。本文介紹在VC++6.0中以CListCtrl類爲基類構建可直接編輯的列表控件類的方法,並提供一個可運行的實例。
關鍵詞 CListCtrl,列表控件,直接編輯,VC++6.0

 
一、引言
    列表控件主要用來以各種方式顯示一組數據記錄供用戶進行各種操作,是最常見的控件之一。WindowsXP資源管理器中的“查看”菜單下的 “圖標|平鋪|列表|詳細信息”就是一個非常典型的應用。MFC中的CListCtrl類提供了對列表控件操作的基本方法,包括插入一個新的項目InsertItem、刪除一個項目DeleteItem、排序項目SortItems等,但CListCtrl類不支持對項目的直接編輯,只能用SetItem或者SetItemText來輸入數據,使用起來非常不方便。下面介紹在VC++6.0中以CListCtrl類爲基類構建可直接編輯的列表控件類的方法,並提供一個可運行的實例。
二、實現方法
    以在列表控件中實現CEditBox的直接編輯爲例,介紹構建可直接編輯的列表控件類CEditListCtrl的方法:
在CEditListCtrl類中設置一個指向編輯框控件的指針m_edit,當列表控件中的一個子項目被兩次不連續的單擊後,使用m_edit在該子項目處創建一個編輯框,編輯框的大小與子項目的大小一致。當向編輯框中輸入數據後,單擊列表控件,便可將編輯框中的數據寫回對應的子項目,同時釋放m_edit所佔用的空間。
    當列表控件中的項目通過滾動條滾動時,某一子項目恰好處於編輯狀態,則此時該子項目所對應的編輯框也要跟着滾動。爲此,在CEditListCtrl類中添加WM_HSCROLL和 WM_VSCROLL消息處理函數,實現編輯框控件和其所對應的子項目的同步滾動。
    在使用列表控件顯示數據時,往往只需要編輯部分列中的數據,有些列的數據則不需要進行編輯。爲此,在CEditListCtrl類中添加一個數據成員BOOL *m_isedit,m_isedit是一個數組,用於標誌某一列是否可以進行直接編輯,若m_isedit[i]爲TRUE,則第i列可以進行直接編輯,否則,反之。CEditListCtrl類中新增的成員函數SetEditColomn用於設置m_isedit的值。
以上方法也可用於在列表控件中實現ComboBox、DropdownList、CheckBox、PushButton等的直接編輯。
三、CEditListCtrl類的定義和實現
    在VC++6.0中創建一個基於對話框的工程,點擊菜單“插入->類”,在彈出的對話框中設置基類爲CLlistCtrl,派生類爲CEditListCtrl。在CEditListCtrl類中定義四個數據成員:
 CEdit * m_edit;//指向編輯框,初值爲NULL
BOOL * m_isedit;//允許進行編輯的列,初值爲NULL
 int m_item;//當前編輯的行號,初值爲-1
 int m_subitem;//當前編輯的列號,初值爲-1
    定義一個常量ID_LISTEDIT作爲m_edit所指向的編輯框的ID號。在CEditListCtrl中添加NM_CLICK的消息處理函數,實現代碼如下:
void CEditListCtrl::OnClick(NMHDR* pNMHDR, LRESULT* pResult)
{
 if(!m_isedit) return;
 NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
 if(!m_edit)
 {
  m_subitem=pNMListView->iSubItem;
  if(pNMListView->iItem!=m_item)
  {
   m_item=pNMListView->iItem;//標誌被單擊的項目
   return;
  }
 }
 if(!m_isedit[m_subitem])//若當前列不允許直接編輯,則返回
  return;
 RECT m_itemrect,m_r;
 GetItemRect(m_item ,&m_itemrect,2);
 GetItemRect(0 ,&m_r,2);
 int m_height=m_itemrect.bottom -m_itemrect.top ;
 int x=m_r.left ,y=m_r.top,cx,cy;//(x,y,cx,cy)爲編輯框顯示的位置
 for(int i=0;i< m_item;i++)
  y+=m_height;
 cy=y+m_height;
 for(i=0;i<m_subitem;i++)
  x+=GetColumnWidth(i);
 cx=x+GetColumnWidth(i);
 if(m_edit)//若編輯框已存在。
 {
  CString s1;
  s1.Format ("%d %d %d %d",x,y,cx,cy);
  m_edit->MoveWindow(x,y,cx-x,cy-y);//移動到當前子項目的位置。
      Invalidate();//刷新屏幕。
  return;
 }
 //若編輯框不存在,則創建編輯框,並在當前子項目處顯示編輯框。
 CRect rect(x,y,cx,cy);
 m_edit=new CEdit();
 m_edit->Create (WS_CHILD|WS_VISIBLE|WS_BORDER,rect,this,ID_LISTEDIT);
 CString str=GetItemText (pNMListView->iItem,pNMListView->iSubItem);
 m_edit->UpdateData(0);
 m_edit->SetWindowText(str); 
 DWORD  dwSel = m_edit->GetSel();  
 m_edit->SetSel(HIWORD(dwSel), -1);  
 m_edit->ShowWindow (SW_SHOW);//顯示編輯框。
 m_edit->SetFocus ();
 *pResult = 0;
}
在CEditListCtrl中添加NM_SETFOCUS的消息處理函數,實現代碼如下:
void CEditListCtrl::OnSetfocus(NMHDR* pNMHDR, LRESULT* pResult)
{
 if(m_edit)
 {//將編輯框中的數據寫回對應的子項目中
  UpdateData( );
  CString str;
  m_edit->GetWindowText(str);
  SetItemText(m_item,m_subitem,str);
  delete m_edit;
  m_edit=NULL;
 }
 *pResult = 0;
}
    添加WM_HSCROLL和 WM_VSCROLL的消息處理函數,實現代碼如下:
void CEditListCtrl::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{//水平滾動時,移動已顯示的編輯框。
 CListCtrl::OnHScroll(nSBCode, nPos, pScrollBar);
 LRESULT* pResult=new LRESULT;
 if(m_edit)  OnClick((NMHDR*)this,pResult) ;
}
void CEditListCtrl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{//垂直滾動時,移動已顯示的編輯框。
 CListCtrl::OnVScroll(nSBCode, nPos, pScrollBar);
 LRESULT* pResult=new LRESULT;
 if(m_edit)
 {
  RECT m_itemrect,m_headrect;
  GetItemRect(m_item ,&m_itemrect,2);
  GetHeaderCtrl()->GetWindowRect(&m_headrect);
  if(m_itemrect.top<m_headrect.bottom-m_headrect.top)
  {
   RECT m_rect;
   m_edit->GetWindowRect(&m_rect);
   m_edit->MoveWindow(m_rect.left,-(m_rect.bottom-m_rect.top),m_rect.right,0);
  }
        else 
  {
   OnClick((NMHDR*)this,pResult) ;
  }
 }
}
    添加SetEditColomn函數,實現代碼如下:
void CEditListCtrl::SetEditColomn(int col,BOOL edit)
{//設置允許直接進行編輯的列
 if(!m_isedit)
 {
  int len=GetHeaderCtrl()->GetItemCount();
  m_isedit=new BOOL[len];
  for(int i=0;i<len;i++)//初始化m_isedit。
   m_isedit[i]=FALSE;
 }
 m_isedit[col]=edit;
}
    重載DestroyWindow()函數,實現代碼如下:
BOOL CEditListCtrl::DestroyWindow()
{
 delete [] m_isedit; 
 return CListCtrl::DestroyWindow();
}
四、CEditListCtrl類的測試
    在上述工程的主對話框中添加一個ListCtrl控件,設置控件的顯示方式爲LVS_REPORT方式,給該控件定義一個CEditListCtrl類型的對象m_list,再在對話框的初始化函數中添加初始化代碼:
m_list.InsertColumn (0,"學號", LVCFMT_LEFT,50);
m_list.InsertColumn (1,"姓名", LVCFMT_LEFT,90);
m_list.InsertColumn (2,"年齡", LVCFMT_LEFT,50);
m_list.InsertItem (0,"1");
m_list.SetItemText (0,1,"王明");
m_list.SetItemText (0,2,"23");
m_list.InsertItem (1,"2");
m_list.SetItemText (1,1,"趙可");
m_list.SetItemText (1,2,"20");
m_list.SetExtendedStyle(LVS_EX_FULLROWSELECT);
m_list.SetEditColomn (0,TRUE);//允許第0列可直接編輯
m_list.SetEditColomn (1,TRUE); //允許第1列可直接編輯
m_list.SetEditColomn (2,TRUE); //允許第2列可直接編輯
    本文中的編碼在Window2000中調試通過,運行結果:當兩次不連續地單擊列表控件中的一個子項目後,該子項目便呈現編輯狀態,如下圖所示。向編輯框中輸入數據後單擊列表控件,便完成對子項目的編輯。

 

                     程序運行效果
五、結語
    本文介紹了在VC++6.0下以CListCtrl類爲基類,構建可直接編輯的列表控件類的方法,非常方便地實現了對列表控件的直接編輯。本文介紹的方法也可用於實現對樹型控件的直接編輯。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章