MFC下,提供了List Control控件,当选择Report模式时,可以方便的做数据报表之类的应用。
但是有个不大不小的问题是,当List Control选择可编辑模式时,只有每一行的第一列的单元格才能编辑,而且在默认情况下,当选中的时候,也只有被选中的这一行的第一个单元格才会反色显示~~这未免太BT了~
在网上找了一些相关的帖子,解决整行选中的问题可以采用为List Control控件增加LVS_EX_FULLROWSELECT样式的方法来实现:
m_Result.SetExtendedStyle(m_Result.GetExtendedStyle() | LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT | LVS_EX_HEADERDRAGDROP | LVS_EX_TWOCLICKACTIVATE);
上面的代码中,LVS_EX_GRIDLINES是希望显示网格;LVS_EX_FULLROWSELECT是希望被选中时整行反色显 示;LVS_EX_HEADERDRAGDROP是让其支持点击表头排序;LVS_EX_TWOCLICKACTIVATE是希望有鼠标在未被选中的行上 移动的时候有一些效果~
整行选中的效果算是搞定了,接下来做任意单元格的编辑~
MFC的List Control控件本身是没有办法达到这个目的了,那怎么办呢?一个比较简单的方法是:虚拟出来一个编辑框,覆盖到被编辑的单元格上 :-)
所以,接下来的工作就是,基于CListCtrl类创建一个自己的ListCtrl类,并重载它的鼠标点击事件处理函数,以便判断用户需要修改的单元格,并动态显示或隐藏一个文本框,用来表示需要编译的单元格~
首先创建自己的类:
1
#if !defined(AFX_MYLISTCTRL_H__7FDA9396_E298_4F10_B778_EB8ADFD82F9A__INCLUDED_)
2
#define
AFX_MYLISTCTRL_H__7FDA9396_E298_4F10_B778_EB8ADFD82F9A__INCLUDED_
3
4
#if _MSC_VER > 1000
5
#pragma
once
6
#endif
// _MSC_VER > 1000
7
//
MyListCtrl.h : header file
8
//
9
#define IDC_MY_LIST_EDITBOX
0xffff
10
11
#define MLSM_ITEMCHANGED (WM_USER
+ 200)
12
/**//////////////////////////////////////////////////////////////////////////////
13
// CMyListCtrl window
14
15
class
CMyListCtrl : public CListCtrl
16

{
17
// Construction
18
public:
19
CMyListCtrl();
20
21
// Attributes
22
public:
23
// Operations
24
public:
25
26
//
Overrides
27
// ClassWizard generated virtual function overrides
28
//{{AFX_VIRTUAL(CMyListCtrl)
29
public:
30
virtual BOOL PreTranslateMessage(MSG* pMsg);
31
//}}AFX_VIRTUAL
32
33
// Implementation
34
public:
35
virtual
~CMyListCtrl();
36
37
// Generated message map functions
38
protected:
39
CEdit m_EditItem;
40
int m_Row;
41
int m_Col;
42
//{{AFX_MSG(CMyListCtrl)
43
afx_msg
void OnLButtonDown(UINT nFlags, CPoint point);
44
afx_msg
void OnLButtonDblClk(UINT nFlags, CPoint point);
45
//}}AFX_MSG
46
47
DECLARE_MESSAGE_MAP()
48
};
49
50
/**//////////////////////////////////////////////////////////////////////////////
51
52
//{{AFX_INSERT_LOCATION}}
53
// Microsoft Visual C++ will
insert additional declarations immediately before the previous line.
54
55
#endif
// !defined(AFX_MYLISTCTRL_H__7FDA9396_E298_4F10_B778_EB8ADFD82F9A__INCLUDED_)
其中需要重载或定义的关键的几个成员:
CEdit m_EditItem;
int m_Row;
int m_Col;
//{{AFX_MSG(CMyListCtrl)
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point);
virtual BOOL PreTranslateMessage(MSG* pMsg);
m_EditItem是用来做编辑动作的文本框;
m_Row和m_Col用来标识需要编辑的单元格,以便在不同的成员函数之间传递;
OnLButtonDown用来处理鼠标左键单击事件;
OnLButtonDblClk用来处理鼠标左键双击事件;
PreTrahslateMessage函数用来截获按键事件,主要用来截获回车和ESC键,表示在编辑过程中确认修改或者取消修改
在鼠标左键双击事件中,主要的任务是需要判断被双击的单元格,如果单元格有效,则需要进入编辑模式,并显示文本框用来响应用户的输入,代码如下:
1
void CMyListCtrl::OnLButtonDblClk(UINT
nFlags, CPoint point)
2

{
3
// TODO: Add your message handler code here and/or call default
4
LVHITTESTINFO hi;
5
hi.pt
= point;
6
7
if(SubItemHitTest(&hi)
!= -1 )
8
{
9
m_Row
= hi.iItem;
10
m_Col
= hi.iSubItem;
11
if(m_EditItem.m_hWnd
== NULL)
12
{
13
RECT rect;
14
rect.left
= rect.top
= 0;
15
rect.bottom
= 20;
16
rect.right
= 100;
17
m_EditItem.Create(WS_CHILD
| ES_LEFT
| WS_BORDER
| ES_AUTOHSCROLL
| ES_WANTRETURN
| ES_MULTILINE, rect,
this, IDC_MY_LIST_EDITBOX);
18
m_EditItem.SetFont(this->GetFont(),
FALSE);
19
}
20
CRect rect;
21
GetSubItemRect(hi.iItem, hi.iSubItem, LVIR_BOUNDS, rect);
22
m_EditItem.SetWindowText(this->GetItemText(hi.iItem,
hi.iSubItem));
23
m_EditItem.MoveWindow(&rect,
TRUE);
24
m_EditItem.ShowWindow(1);
25
}
26
CListCtrl::OnLButtonDblClk(nFlags, point);
27
}
在鼠标单击事件中,我们需要判断用户单击的是不是其他的单元格,如果是,表示用户希望退出编辑模式了,此时,需要保存编辑之后的文本:
1
void
CMyListCtrl::OnLButtonDown(UINT nFlags, CPoint point)
2

{
3
// TODO: Add your message handler code here and/or call default
4
if(m_EditItem.m_hWnd
!= NULL)
5
{
6
m_EditItem.ShowWindow(0);
7
if(m_Row
!= -1)
8
{
9
CString ItemText;
10
m_EditItem.GetWindowText(ItemText);
11
this->SetItemText(m_Row, m_Col, ItemText);
12
::PostMessage(GetParent()->m_hWnd,
MLSM_ITEMCHANGED, (WPARAM)MAKELONG(m_Row, m_Col), (LPARAM)this->m_hWnd);
13
}
14
}
15
m_Col
= m_Row
= -1;
16
CListCtrl::OnLButtonDown(nFlags, point);
17
}
在PreTranslateMessage函数中,需要截获按键时间中的回车键和ESC键,并保存或取消编辑:
1
BOOL
CMyListCtrl::PreTranslateMessage(MSG* pMsg)
2

{
3
// TODO: Add your specialized code here and/or call the base class
4
BOOL bHandledMsg
= FALSE;
5
6
if(pMsg->hwnd
== m_EditItem.m_hWnd)
7
{
8
switch (pMsg->message)
9
{
10
case WM_KEYDOWN:
11
{
12
switch (pMsg->wParam)
13
{
14
case VK_RETURN://回车
15
if(m_Row
!= -1)
16
{
17
CString ItemText;
18
m_EditItem.GetWindowText(ItemText);
19
this->SetItemText(m_Row, m_Col, ItemText);
20
::PostMessage(GetParent()->m_hWnd,
MLSM_ITEMCHANGED, (WPARAM)MAKELONG(m_Row, m_Col), (LPARAM)this->m_hWnd);
21
}
22
case VK_ESCAPE://ESC键
23
m_EditItem.ShowWindow(0);
24
m_Col
= m_Row
= -1;
25
bHandledMsg
= TRUE;
26
break;
27
default:
28
break;
29
}
30
}//
case WM_KEYDOWN
31
break;
32
default:
33
break;
34
}//
switch(pMsg->message)
35
}//
if(pMsg->hwnd
36
return (bHandledMsg
? TRUE : CListCtrl::PreTranslateMessage(pMsg));
37
}
OK,一个可以支持编辑的List Control控件就制作完成了,试试吧 :-)
本文介绍如何在MFC框架下实现一个可编辑的ListControl控件,通过自定义CMyListCtrl类并重载鼠标点击事件处理函数,使得任意单元格均可编辑。
592

被折叠的 条评论
为什么被折叠?



