Introduction
Almost every one of us who are programming in VC++ , will come across the List control. There are many cases where there is a need to represent data in List Control in multiple columns. By default it is not possible to modify the data in the List control itself. In this small article I am putting a simple way to edit any value in any column in a Report style List control. The logic here is simple, whenever user clicks on an sub-item which he wants to modify at that place I am displaying a edit box and allowing to modify the value. Once modified and by clicking the ENTER key, the updated value is set in the List control. Here I am assuming the user is familiar with VC++ and using Class Wizard
Implementation steps:
- Using MFC AppWizard, create a Dialog Based application. Give the application name as MultipleColumns. By default the wizard adds OK and Cancel buttons to the Dialog, Remove these two buttons.
- Now Add a List-Control and in properties change the style to Report, this style is necessary if we want multiple columns
- Add two buttons to the Dialog and name them as OK and Exit
- Add one Edit box and in the properties remove the Border style
- Using the Class Wizard add the message handlers for the OK and Exit Buttons. Add the following code to those functions
- Add a function called
InsertItems()
to theCMulipleColumnsDlg
class. - Add another function called
SetCell( )
to theCMultipleColumnsDlg
class - Add one more function called
GetItemText()
to the same Class - Also add two member variables to the
CMultipleColumnsDlg
class which are of typeint
- From the Class wizard add
NM_CLICK
notification to the List control. Inside the function handler write the following code - To handle the ENTER key we need to write the virtual function
OnOk
in the MultipleColumnsDlg.h, so add the following as protected member - The last step in the implementation is add the following code in side the
OnInitDialog
function
![](http://www.codeproject.com/images/minus.gif)
1
2
3
4
5 |
void CMultipleColumnsDlg::OK() { CDialog::EndDialog (0); // Add this line } |
![](http://www.codeproject.com/images/minus.gif)
1
2
3
4
5 |
void CMultipleColumnsDlg::OnExit() { CDialog::EndDialog (0); // Add this line } |
![](http://www.codeproject.com/images/minus.gif)
1 |
void InsertItems(); |
In the function handler add the following code
![](http://www.codeproject.com/images/minus.gif)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70 |
// This function inserts the default values // into the listControl void CMultipleColumnsDlg::InsertItems() { HWND hWnd = ::GetDlgItem(m_hWnd, IDC_LIST1); // Set the LVCOLUMN structure with the required // column information LVCOLUMN list; list.mask = LVCF_TEXT |LVCF_WIDTH| LVCF_FMT |LVCF_SUBITEM; list.fmt = LVCFMT_LEFT; list.cx = 50; list.pszText = "S.No" ; list.iSubItem = 0; //Inserts the column ::SendMessage(hWnd,LVM_INSERTCOLUMN, ( WPARAM )0,( WPARAM )&list); list.cx = 100; list.pszText = "Name" ; list.iSubItem = 1; ::SendMessage(hWnd ,LVM_INSERTCOLUMN, ( WPARAM )1,( WPARAM )&list); list.cx = 100; list.pszText = "Address" ; list.iSubItem = 2; ::SendMessage(hWnd ,LVM_INSERTCOLUMN, ( WPARAM )1,( WPARAM )&list); list.cx = 100; list.pszText = "Country" ; list.iSubItem = 2; ::SendMessage(hWnd ,LVM_INSERTCOLUMN, ( WPARAM )1,( WPARAM )&list); // Inserts first Row with four columns . SetCell(hWnd, "1" ,0,0); SetCell(hWnd, "Prabhakar" ,0,1); SetCell(hWnd, "Hyderabad" ,0,2); SetCell(hWnd, "India" ,0,3); // Inserts second Row with four columns . SetCell(hWnd, "2" ,1,0); SetCell(hWnd, "Uday" ,1,1); SetCell(hWnd, "Chennai" ,1,2); SetCell(hWnd, "India" ,1,3); // Inserts third Row with four columns . SetCell(hWnd, "3" ,2,0); SetCell(hWnd, "Saradhi" ,2,1); SetCell(hWnd, "Bangolore" ,2,2); SetCell(hWnd, "India" ,2,3); // Inserts fourth Row with four columns . SetCell(hWnd, "4" ,3,0); SetCell(hWnd, "Surya" ,3,1); SetCell(hWnd, "Calcutta" ,3,2); SetCell(hWnd, "India" ,3,3); } |
![](http://www.codeproject.com/images/minus.gif)
1 |
void SetCell( HWND hWnd1, CString value, int nRow, int nCol); |
In the function handler add the following code
![](http://www.codeproject.com/images/minus.gif)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 |
// This function set the text in the specified // SubItem depending on the Row and Column values void CMultipleColumnsDlg::SetCell( HWND hWnd1, CString value, int nRow, int nCol) { TCHAR szString [256]; wsprintf(szString,value ,0); //Fill the LVITEM structure with the //values given as parameters. LVITEM lvItem; lvItem.mask = LVIF_TEXT; lvItem.iItem = nRow; lvItem.pszText = szString; lvItem.iSubItem = nCol; if (nCol >0) //set the value of listItem ::SendMessage(hWnd1,LVM_SETITEM, ( WPARAM )0,( WPARAM )&lvItem); else //Insert the value into List ListView_InsertItem(hWnd1,&lvItem); } |
![](http://www.codeproject.com/images/minus.gif)
1 |
CString GetItemText( HWND hWnd, int nItem, int nSubItem) const ; |
Inside the function add the following code
![](http://www.codeproject.com/images/minus.gif)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 |
//this function will returns the item //text depending on the item and SubItem Index CString CMultipleColumnsDlg::GetItemText( HWND hWnd, int nItem, int nSubItem) const { LVITEM lvi; memset (&lvi, 0, sizeof (LVITEM)); lvi.iSubItem = nSubItem; CString str; int nLen = 128; int nRes; do { nLen *= 2; lvi.cchTextMax = nLen; lvi.pszText = str.GetBufferSetLength(nLen); nRes = ( int )::SendMessage(hWnd, LVM_GETITEMTEXT, ( WPARAM )nItem, ( LPARAM )&lvi); } while (nRes == nLen-1); str.ReleaseBuffer(); return str; } |
![](http://www.codeproject.com/images/minus.gif)
1 |
int nItem, nSubItem; |
![](http://www.codeproject.com/images/minus.gif)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60 |
//This function Displays an EditBox at the position //where user clicks on a particular SubItem with //Rectangle are equal to the SubItem, thus allows to //modify the value void CMultipleColumnsDlg::OnClickList( NMHDR* pNMHDR, LRESULT * pResult) { Invalidate(); HWND hWnd1 = ::GetDlgItem (m_hWnd,IDC_LIST1); LPNMITEMACTIVATE temp = (LPNMITEMACTIVATE) pNMHDR; RECT rect; //get the row number nItem = temp->iItem; //get the column number nSubItem = temp->iSubItem; if (nSubItem == 0 || nSubItem == -1 || nItem == -1) return ; //Retrieve the text of the selected subItem //from the list CString str = GetItemText(hWnd1,nItem , nSubItem); RECT rect1,rect2; // this macro is used to retrieve the Rectanle // of the selected SubItem ListView_GetSubItemRect(hWnd1,temp->iItem, temp->iSubItem,LVIR_BOUNDS,&rect); //Get the Rectange of the listControl ::GetWindowRect(temp->hdr.hwndFrom,&rect1); //Get the Rectange of the Dialog ::GetWindowRect(m_hWnd,&rect2); int x=rect1.left-rect2.left; int y=rect1.top-rect2.top; if (nItem != -1) ::SetWindowPos(::GetDlgItem(m_hWnd,IDC_EDIT1), HWND_TOP,rect.left+x,rect.top+4, rect.right-rect.left - 3, rect.bottom-rect.top -1,NULL); ::ShowWindow(::GetDlgItem(m_hWnd,IDC_EDIT1),SW_SHOW); ::SetFocus(::GetDlgItem(m_hWnd,IDC_EDIT1)); //Draw a Rectangle around the SubItem ::Rectangle(::GetDC(temp->hdr.hwndFrom), rect.left,rect.top-1,rect.right,rect.bottom); //Set the listItem text in the EditBox ::SetWindowText(::GetDlgItem(m_hWnd,IDC_EDIT1),str); *pResult = 0; } |
![](http://www.codeproject.com/images/minus.gif)
1 |
afx_msg void OnOK(); |
In MultipleColumnsDlg.cpp write the following code.
![](http://www.codeproject.com/images/minus.gif)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35 |
// This function handles the ENTER key void CMultipleColumnsDlg::OnOK() { CWnd* pwndCtrl = GetFocus(); // get the control ID which is // presently having the focus int ctrl_ID = pwndCtrl->GetDlgCtrlID(); CString str; switch (ctrl_ID) { //if the control is the EditBox case IDC_EDIT1: //get the text from the EditBox GetDlgItemText(IDC_EDIT1,str); //set the value in the listContorl with the //specified Item & SubItem values SetCell(::GetDlgItem (m_hWnd,IDC_LIST1), str,nItem,nSubItem); ::SendDlgItemMessage(m_hWnd,IDC_EDIT1, WM_KILLFOCUS,0,0); ::ShowWindow(::GetDlgItem(m_hWnd,IDC_EDIT1), SW_HIDE); break ; default : break ; } } |
![](http://www.codeproject.com/images/minus.gif)
1
2
3
4
5
6
7
8 |
//Set the style to listControl ListView_SetExtendedListViewStyle(::GetDlgItem (m_hWnd,IDC_LIST1),LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES); InsertItems(); ::ShowWindow(::GetDlgItem(m_hWnd,IDC_EDIT1),SW_HIDE); |
Conclusion
With this I will hope , it will give an idea to edit any sub items in a List control.
'C & C++ > MFC 컨트롤' 카테고리의 다른 글
[Ctrl] CXListCtrl에 스킨 및 여러가지 컨트롤 적용하기 (0) | 2011.04.14 |
---|---|
[Tip] LED로(7-segment) 숫자를 표시하는 방법 (0) | 2011.04.14 |
[Tip] 일정 시간 경과 후 사라지는 MessageBox (0) | 2011.04.14 |
[Cursor] 시스템 커서 불러오기 (0) | 2011.04.14 |
[Dialog] 프로그램 최소화 원래대로... (0) | 2011.04.14 |
댓글