天天看點

VC++中可編輯的CListCtrl實作

CEditableListCtrl類實作代碼

EditableListCtrl.h檔案

#if!defined(AFX_EDITABLELISTCTRL_H__D931FC67_33E0_4A71_8C4B_2E62FBCA6081__INCLUDED_)

#defineAFX_EDITABLELISTCTRL_H__D931FC67_33E0_4A71_8C4B_2E62FBCA6081__INCLUDED_

#if _MSC_VER > 1000

#pragma once

#endif // _MSC_VER > 1000

// EditableListCtrl.h : headerfile

//

/

// CEditableListCtrl window

class CEditableListCtrl : publicCListCtrl

{

// Construction

public:

    CEditableListCtrl();

// Attributes

public:

// Operations

public:

// Overrides

    //ClassWizard generated virtual function overrides

    //{{AFX_VIRTUAL(CEditableListCtrl)

    public:

    protected:

    virtualvoid PreSubclassWindow();

    //}}AFX_VIRTUAL

// Implementation

public:

    voidShowEditBox(BOOL isShow, CRect *rc);

    virtual~CEditableListCtrl();

    //Generated message map functions

public:

    voidShowEditBox(BOOL isShow, int iItem, int iSubItem);

    //{{AFX_MSG(CEditableListCtrl)

    afx_msgvoid OnDblclk(NMHDR* pNMHDR, LRESULT* pResult);

    afx_msgvoid OnEditKillFocus();

    afx_msgvoid OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);

    afx_msgvoid OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);

    afx_msgBOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt);

    //}}AFX_MSG

    DECLARE_MESSAGE_MAP()

private:

    intm_CurSelSubItem;//記錄目前選擇的子項

    intm_CurSelItem;//記錄目前選擇的項

    CEditm_Edit;

};

#define    UM_LISTEDIT_KILLFOCUS    WM_USER+ 1

#define UM_LISTEDIT_DBCLICK     WM_USER + 2

/

//{{AFX_INSERT_LOCATION}}

// Microsoft Visual C++ willinsert additional declarations immediately before the previous line.

#endif //!defined(AFX_EDITABLELISTCTRL_H__D931FC67_33E0_4A71_8C4B_2E62FBCA6081__INCLUDED_)

EditableListCtrl.cpp檔案

// EditableListCtrl.cpp:implementation of the CEditableListCtrl class.

//

//

#include "stdafx.h"

#include "****.h"

#include"EditableListCtrl.h"

#ifdef _DEBUG

#undef THIS_FILE

static char THIS_FILE[]=__FILE__;

#define new DEBUG_NEW

#endif

//

// Construction/Destruction

//

CEditableListCtrl::CEditableListCtrl()

{

    m_CurSelSubItem= -1;

    m_CurSelItem= -1;

}

CEditableListCtrl::~CEditableListCtrl()

{

}

BEGIN_MESSAGE_MAP(CEditableListCtrl,CListCtrl)

    //{{AFX_MSG_MAP(CEditableListCtrl)

    ON_NOTIFY_REFLECT(NM_DBLCLK,OnDblclk)

    ON_EN_KILLFOCUS(IDC_LISTEDIT,OnEditKillFocus)

    ON_WM_HSCROLL()

    ON_WM_VSCROLL()

    ON_WM_MOUSEWHEEL()

    //}}AFX_MSG_MAP

END_MESSAGE_MAP()

/

// CEditableListCtrl messagehandlers

//顯示編輯框

voidCEditableListCtrl::ShowEditBox(BOOL isShow, CRect *rc)

{

    ASSERT((isShow&& (rc != NULL)) || !isShow);

    if(rc!= NULL)

       m_Edit.MoveWindow(rc->left,rc->top, rc->right, rc->bottom, TRUE);

    if(isShow)

    {

       m_Edit.SetFocus();

       m_Edit.ShowWindow(SW_SHOW);

    }

    elseif(!isShow)

       m_Edit.ShowWindow(SW_HIDE);

}

//滑鼠輕按兩下事件處理函數

voidCEditableListCtrl::OnDblclk(NMHDR* pNMHDR, LRESULT* pResult)

{

    //TODO: Add your control notification handler code here

    LPNMLISTVIEWlpnmlv = (LPNMLISTVIEW)pNMHDR;

    if(lpnmlv->iItem>= 0)

    {

       CRectrc;

       CWnd*wnd = GetParent();

       m_CurSelItem= lpnmlv->iItem;

       m_CurSelSubItem= lpnmlv->iSubItem;

       CStringstr = GetItemText(m_CurSelItem, m_CurSelSubItem);

       m_Edit.SetWindowText(str);

       m_Edit.SetSel(0,-1);

       GetSubItemRect(lpnmlv->iItem,lpnmlv->iSubItem, LVIR_LABEL, rc);

       rc.bottom= rc.bottom - rc.top;

       rc.right= rc.right - rc.left;

       ShowEditBox(TRUE,&rc);

       wnd->SendMessage(UM_LISTEDIT_DBCLICK,(WPARAM)lpnmlv, 0);

    }

    *pResult= -1;

}

//重寫父類虛函數,初始化CEdit

voidCEditableListCtrl::PreSubclassWindow()

{

    //TODO: Add your specialized code here and/or call the base class

    RECTrc = {0};

    m_Edit.Create(WS_CHILD|WS_TABSTOP  | WS_VISIBLE |ES_LEFT, rc,this, IDC_LISTEDIT);

    CListCtrl::PreSubclassWindow();

}

//編輯框焦點失去處理函數,需要手動添加函數和消息映射

void CEditableListCtrl::OnEditKillFocus()

{

    CStringstr;

    CWnd*wnd;

    wnd= GetParent();

    ShowEditBox(FALSE,NULL);

    m_Edit.GetWindowText(str);

    SetItemText(m_CurSelItem,m_CurSelSubItem, str.GetBuffer(0));

    ::SendMessage(wnd->m_hWnd,UM_LISTEDIT_KILLFOCUS,

       m_CurSelItem,m_CurSelSubItem);

    m_CurSelItem= -1;

    m_CurSelSubItem= -1;

    m_Edit.SetWindowText("");

}

voidCEditableListCtrl::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)

{

    //TODO: Add your message handler code here and/or call default

    SetFocus();

    CListCtrl::OnHScroll(nSBCode,nPos, pScrollBar);

}

voidCEditableListCtrl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)

{

    //TODO: Add your message handler code here and/or call default

    SetFocus();

    CListCtrl::OnVScroll(nSBCode,nPos, pScrollBar);

}

BOOLCEditableListCtrl::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)

{

    //TODO: Add your message handler code here and/or call default

    SetFocus();

    returnCListCtrl::OnMouseWheel(nFlags, zDelta, pt);

}

//直接根據參數設定CEdit顯示内容,isShow是否顯示,item項,isubitem子項,未使用

voidCEditableListCtrl::ShowEditBox(BOOL isShow, int iItem, int iSubItem)

{

    CStringcon;

    CRectrc;

    if(!isShow)

    {

       m_Edit.ShowWindow(SW_HIDE);

       return;

    }

    con= GetItemText(iItem, iSubItem);

    GetSubItemRect(iItem,iSubItem, LVIR_LABEL, rc);

    m_Edit.SetWindowText(con);

    m_Edit.SetFocus();

    m_Edit.SetSel(0,-1);

    m_Edit.MoveWindow(rc.left,rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE);

    m_Edit.ShowWindow(SW_SHOW);

}

相關資料(清單控件中指定列可被編輯)

一、引言

    清單控件主要用來以各種方式顯示一組資料記錄供使用者進行各種操作,是最常見的控件之一。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的消息處理函數,實作代碼如下:

voidCEditListCtrl::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);

intm_height=m_itemrect.bottom-m_itemrect.top ;

intx=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);

CStringstr=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的消息處理函數,實作代碼如下:

voidCEditListCtrl::OnHScroll(UINT nSBCode,UINT nPos, CScrollBar* pScrollBar) 

{//水準滾動時,移動已顯示的編輯框。

CListCtrl::OnHScroll(nSBCode,nPos,pScrollBar);

LRESULT* pResult=new LRESULT;

if(m_edit)OnClick((NMHDR*)this,pResult) ;

}

voidCEditListCtrl::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函數,實作代碼如下:

voidCEditListCtrl::SetEditColomn(intcol,BOOL edit)

{//設定允許直接進行編輯的列

if(!m_isedit)

{

intlen=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()函數,實作代碼如下:

BOOLCEditListCtrl::DestroyWindow() 

{

delete [] m_isedit; 

returnCListCtrl::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中調試通過,運作結果:當兩次不連續地單擊清單控件中的一個子項目後,該子項目便呈現編輯狀态,如下圖所示。向編輯框中輸入資料後單擊清單控件,便完成對子項目的編輯。

c �):[email protected] ��z 0); font-family: Arial, Helvetica, sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: -webkit-auto; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); ">}

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中調試通過,運作結果:當兩次不連續地單擊清單控件中的一個子項目後,該子項目便呈現編輯狀态,如下圖所示。向編輯框中輸入資料後單擊清單控件,便完成對子項目的編輯。

繼續閱讀