banner

[Rule] Rules  [Home] Main Forum  [Portal] Portal  
[Members] Member Listing  [Statistics] Statistics  [Search] Search  [Reading Room] Reading Room 
[Register] Register  
[Login] Loginhttp  | https  ]
 
Forum Index Thảo luận hệ điều hành Windows [CListCtrl] Rắc rối khi select một Item or Row - VC8 (MFC)  XML
  [Programming]   [CListCtrl] Rắc rối khi select một Item or Row - VC8 (MFC) 21/05/2008 15:55:00 (+0700) | #1 | 131766
Z0diac
Member

[Minus]    0    [Plus]
Joined: 25/04/2008 02:49:37
Messages: 21
Offline
[Profile] [PM]
Các bạn cho mình hỏi là:
Giả sử như mình có một List Control ở dạng Report như sau, mình set chế độ FULLROWSELECT.

Code:
[Màu]  [Chất Liệu]
 1   Xanh    Vải
 2   Đỏ        Da
 3   Vàng    Giấy

Bây giờ nếu như mình chọn Row 2 (Đỏ, Da) để xử lý một tình huống nào đó. Vậy làm cách nào để nhận ra được sự kiện mình chọn Row 2 đó, để có thể đưa ra một ứng xử như mình mong muốn.

Em đã dùng sự kiện LVN_ItemChanged để thử tìm hiểu xem như sau :


Code:
CAppDlg::OnLvnItemchangedListname(NMHDR *pNMHDR, LRESULT *pResult)
{
     LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
     int m_Selected = pNMLV->iItem;
     CString strMsg;
     strMsg.Format(_T("Chon row %i),m_Selected);
     MessageBox(strMsg,_T("Msg"),MB_OK);
}

Khi em chạy thử và chọn thử một Row nào đó ( lần chọn thứ i) thì nó sẽ xuất hiện 3 lần MessageBox. Và em để ý thấy là 2 MessageBox đầu đều thông báo về Row mà mình đã chọn ở lần (i-1). Em không hiểu tại sao lại xảy ra như vậy, vậy mình có thể biết được chính xác iItem của Row mình đang chọn ko?Và có cách nào khắc phục không ạ tình trạng này ko ah?
[Up] [Print Copy]
  [Question]   Re: [CListCtrl] Rắc rối khi select một Item or Row - VC8 (MFC) 21/05/2008 23:39:12 (+0700) | #2 | 131831
[Avatar]
Z0rr0
Q+WRtaW5pc3RyYXRvc+g

Joined: 14/08/2002 12:52:01
Messages: 1323
Location: Underground
Offline
[Profile] [PM] [WWW] [Yahoo!]
Khi chọn lựa một item trên listcontrol, nó sẽ thông báo LVN_ITEMCHANGED rằng:
- Item cũ đã thay đổi trạng thái, tức là ko còn được chọn
- Item mới được chọn - trạng thái mới

Lý do đó nên LVN_ITEMCHANGED được gửi nhiều lần, bồ debug sẽ thấy các giá trị chi tiết trong cấu trúc NMLISTVIEW gửi kèm thông điệp LVN_ITEMCHANGED.

Có nhiều cách giải quyết, nếu dùng LVN_ITEMCHANGED thì cần lưu trữ giá trị item cũ và so sánh khi nhận được LVN_ITEMCHANGED, nếu thay đổi mới xử lý (tức là thật sự item được chọn khác với item cũ)
Cách khác tốt hơn là bắt thông điệp NM_CLICK, trong đó sử dụng hàm GetSelectionMark() của ListControl để biết item chính xác vừa được chọn.
Hibernating
[Up] [Print Copy]
  [Question]   Re: [CListCtrl] Rắc rối khi select một Item or Row - VC8 (MFC) 22/05/2008 09:47:26 (+0700) | #3 | 131955
Z0diac
Member

[Minus]    0    [Plus]
Joined: 25/04/2008 02:49:37
Messages: 21
Offline
[Profile] [PM]
Cảm ơn anh Z0rr0 đã trả lời một cách rõ ràng và chi tiết. Em sẽ thử dùng cách bắt thông điệp NM_CLICK thử xem. Hôm qua em cũng đã có thử ngó qua thắng này, nhưng không biết sử dụng hàm GetSelectionMark() để giải quyết.
[Up] [Print Copy]
  [Question]   Re: [CListCtrl] Rắc rối khi select một Item or Row - VC8 (MFC) 22/05/2008 17:10:13 (+0700) | #4 | 132084
Z0diac
Member

[Minus]    0    [Plus]
Joined: 25/04/2008 02:49:37
Messages: 21
Offline
[Profile] [PM]
Sau khi tìm hiểu lại vấn đề này em có thêm một số thắc mắc như sau:
- Đúng là thông điệp NM_CLICK có thể giải quyết tốt yêu cầu này khi ta chỉ dùng sự kiện CLICK chuột. Nhưng nếu ta dùng các mũi tên lên, xuống thì nó lại không thể nhận biết được
- Và em lại thử dùng thằng LVN_ITEMCHANGED một lần nữa. Và đây là cách để biết Row mình đang chọn có Id bao nhiêu :

Code:
LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
CString msg;
if ((pNMLV->uOldState == 0) && (pNMLV->uNewState !=0))
{
  m_Sel = pNMLV->iItem;
  msg.Format(_T("Row %i"),m_Sel);
  MessageBox(msg,_T("MSG"),MB_OK);
}

Nhưng có một điều là, khi mình bắt đầu Run App (hay Load App) thì nó sẽ bắt đầu khởi tạo các Selection cho tất cả các Row, bằng chứng là em dùng hàm MessageBox như trên thì nó lại tiếp tục để kiểm tra. Vậy có cách nào để deselection trước khi mình thật sự chọn theo ý mình không? Em có coi qua cấu trúc và thử dùng hàm SelItemState nhưng cũng ko được.

- Và điều cuối cùng là, nếu em sau khi em chọn một Row nào đó, và em nhấn phím ENTER một cái thì lập tức App bị đóng lại ngay? Cho em hỏi đây là lỗi gì? Do cái gì gây ra và cách khắc phục như thế nào.Em không có 2 hàm OnOK()hay OnCancel().
App của em là một dạng Dialog. Em có dùng Tab Control (em ko dùng PropertPage để tạo các Tab). Sau đây là đoạn code tạo List Report của em :

Code:
void CDialogA::OnInitDialog()
{
.....
CRect rect;
	m_ListCtrl.GetClientRect(&rect);
	int m_Width = rect.Width()/7;
	m_ListCtrl.SetExtendedStyle( LVS_EX_CHECKBOXES |LVS_EX_FULLROWSELECT |LVS_EX_GRIDLINES |);
	m_ListCtrl.InsertColumn(0,_T("Mau"),LVCFMT_LEFT,m_Width);
	m_ListCtrl.InsertColumn(1,_T("Chat Lieu"),LVCFMT_LEFT,m_Width*4.8);
	m_ListCtrl.InsertColumn(2,_T("Gia Tien"),LVCFMT_LEFT,m_Width*1.2);
    int m_ListItem = 3;
    LVITEM lvi;
    CString strItem;
    for (int i = 0;i<m_ListItem;i++)
   {
      lvi.mask= LVIF_TEXT;
      strItem.Format(_T("Item %i"),i);
      lvi.iItem=i;
      lvi.iSubItem=0;	
      lvi.pszText = (LPTSTR)(LPCTSTR)(strItem);
      m_ListCtrl.InsertItem(&lvi);		
      strItem.Format(_T("%d"), 10*i);
      lvi.iSubItem =1;	
      lvi.pszText = (LPTSTR)(LPCTSTR)(strItem);
      m_ListCtrl.SetItem(&lvi);
  }
}
[Up] [Print Copy]
  [Question]   Re: [CListCtrl] Rắc rối khi select một Item or Row - VC8 (MFC) 23/05/2008 07:21:02 (+0700) | #5 | 132242
[Avatar]
Z0rr0
Q+WRtaW5pc3RyYXRvc+g

Joined: 14/08/2002 12:52:01
Messages: 1323
Location: Underground
Offline
[Profile] [PM] [WWW] [Yahoo!]
Sau khi tìm hiểu lại vấn đề này em có thêm một số thắc mắc như sau:
- Đúng là thông điệp NM_CLICK có thể giải quyết tốt yêu cầu này khi ta chỉ dùng sự kiện CLICK chuột. Nhưng nếu ta dùng các mũi tên lên, xuống thì nó lại không thể nhận biết được 

Em vẫn có thể dùng LVN_ITEMCHANGED (cần thêm vài thủ tục kiểm tra) hoặc dùng LVN_KEYDOWN.


- Và em lại thử dùng thằng LVN_ITEMCHANGED một lần nữa. Và đây là cách để biết Row mình đang chọn có Id bao nhiêu :

Code:
LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
CString msg;
if ((pNMLV->uOldState == 0) && (pNMLV->uNewState !=0))
{
  m_Sel = pNMLV->iItem;
  msg.Format(_T("Row %i"),m_Sel);
  MessageBox(msg,_T("MSG"),MB_OK);
}

Nhưng có một điều là, khi mình bắt đầu Run App (hay Load App) thì nó sẽ bắt đầu khởi tạo các Selection cho tất cả các Row, bằng chứng là em dùng hàm MessageBox như trên thì nó lại tiếp tục để kiểm tra. Vậy có cách nào để deselection trước khi mình thật sự chọn theo ý mình không? Em có coi qua cấu trúc và thử dùng hàm SelItemState nhưng cũng ko được. 

Em mô tả khó hiểu.
Ngầm định khi listcontrol được tạo và thêm dữ liệu, không có item nào được chọn cả, trừ khi em gọi chọn (vd SetSelectionMark, change state, ...) một item nào đó.

- Và điều cuối cùng là, nếu em sau khi em chọn một Row nào đó, và em nhấn phím ENTER một cái thì lập tức App bị đóng lại ngay? Cho em hỏi đây là lỗi gì? Do cái gì gây ra và cách khắc phục như thế nào.Em không có 2 hàm OnOK()hay OnCancel(). 

Không lỗi gì cả, do thiết kế (design) cho dialog nó vậy, ngầm định phím ENTER trong dialog sẽ tự động gửi cho default button (OK) và sẽ tự gọi OnOK để thoát. Em chỉ việc handle hàm OnOK, bỏ đoạn gọi đến CDialog::OnOK là được.
Hibernating
[Up] [Print Copy]
  [Question]   Re: [CListCtrl] Rắc rối khi select một Item or Row - VC8 (MFC) 23/05/2008 08:27:54 (+0700) | #6 | 132259
Z0diac
Member

[Minus]    0    [Plus]
Joined: 25/04/2008 02:49:37
Messages: 21
Offline
[Profile] [PM]
- Anh Z0rr0 xem đoạn code tạo List Control của em đấy, em tạo nó một cách bình thường, nhưng không hiểu sao khi em dùng LVN_ITEMCHANGED để xác định Row mà mình đang select thì khi em chạy Run(Ctrl + F5 trong môi trường VC 8) thì nó sẽ xuất hiện 3 lần Message Box rồi mới xuất hiện cái Dialog của mình.

- Chuyện bị close Dialog khi ấn phím Enter em đã làm được bằng cách override lại hàm OnOk(), hôm qua em quên chọn Buid All nên nó không thực thi. Cảm ơn anh nhé.
[Up] [Print Copy]
  [Question]   Re: [CListCtrl] Rắc rối khi select một Item or Row - VC8 (MFC) 23/05/2008 22:16:22 (+0700) | #7 | 132353
[Avatar]
Z0rr0
Q+WRtaW5pc3RyYXRvc+g

Joined: 14/08/2002 12:52:01
Messages: 1323
Location: Underground
Offline
[Profile] [PM] [WWW] [Yahoo!]
Nguyên nhân do em sử dụng thuộc tính mở rộng LVS_EX_CHECKBOXES cho list control.
Khi đó, mỗi lần InsertItem được gọi sẽ có thêm một WM_NOTIFY message thông báo thay đổi thuộc tính của item là LVN_ITEMCHANGED.
Do đó em sẽ nhận được kết quả trên.
Để tránh chuyện này, có thể dùng một cờ (flag) kiểm tra hoặc không dùng LVN_ITEMCHANGED.
Hibernating
[Up] [Print Copy]
  [Question]   Re: [CListCtrl] Rắc rối khi select một Item or Row - VC8 (MFC) 24/05/2008 11:58:33 (+0700) | #8 | 132500
Z0diac
Member

[Minus]    0    [Plus]
Joined: 25/04/2008 02:49:37
Messages: 21
Offline
[Profile] [PM]
- Yah, em đã làm được rồi. Chỉ việc thêm một biến kiểm tra (gọi là m_ListCtrlInit chẳng hạn) được thiết lập bằng FALSE(List Control chưa được khởi tạo), sau khi khởi tạo xong List Control thì set nó bằng TRUE. Và trong sự kiện LVN_ITEMCHANGED, nếu m_ListCtrlInit = TRUE thì mới bắt đầu xử lý. Kết hợp lại ta sẽ có đoạn code sau

Code:
LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
 CString msg;
if (m_ListCtrlInit)

 {
   m_Sel = pNMLV->iItem;
    if (ListView_GetCheckState(m_ListNamePLR.GetSafeHwnd(), m_Sel)) 
{
msg.Format(_T("Row %i đã Checked"),m_Sel);
MessageBox(msg,_T("Msg"),MB_OK);
}
   else 
{
msg.Format(_T("Row %i đã Unchecked"),m_Sel);
MessageBox(msg,_T("Msg"),MB_OK);
}
		
 }


Vì App của em là một dạng mở rộng LVS_EX_CHECKBOXES, nên tất nhiên là em muốn khi mình Click chuột vào một Check Box nào đó để Checked hay Unchecked thì mình phải biết được trạng thái của nò là Checked hay Unchecked để có thể đưa ra các xử lý như ý mình. Em dùng hàm ListView_GetCheckState() để kiểm tra. Nhưng ngặt một nỗi là nếu để nguyên đoạn code như trên nó sẽ xảy ra tình huống là bị lặp lại 3 lần MessageBox. Còn nếu em thêm một lệnh để xác định Row mình đang chọn như sau :

Code:
if ((pNMLV->uOldState == 0) && (pNMLV->uNewState !=0))


thì khi em Click chuột vào CheckBox thì lại không xảy ra một MessageBox nào, còn Click chuột vào Row thì vẫn hiện ra MessageBox bình thường. Ngoài ra khi thêm đoạn kiểm tra trên vào nó còn một số lỗi ngớ ngẫn khác ví dụ như (Giả sử em đã Click chuột vào Row I và nó đã hiện MessageBox, và CheckBox của Row I đang ở dạng Checked chẳng hạn, nếu giờ em Unchecked cái CheckBox của Row I và Click chuột lại vào Row I đó thì lại không hiện lên Messagebox thông báo, nếu muốn hiện lên Messagebox thì phải Click chuột vào Row khác, sau đó Click chuột lại vào Row này thì mới hiện MessageBox). Em không hiểu tại sao bị như vậy.

[Up] [Print Copy]
  [Question]   Re: [CListCtrl] Rắc rối khi select một Item or Row - VC8 (MFC) 26/05/2008 23:56:25 (+0700) | #9 | 132882
[Avatar]
Z0rr0
Q+WRtaW5pc3RyYXRvc+g

Joined: 14/08/2002 12:52:01
Messages: 1323
Location: Underground
Offline
[Profile] [PM] [WWW] [Yahoo!]
Anh thấy em nên tìm hiểu sâu hơn cơ chế hoạt động của listcontrol, các item state và checkbox smilie
Hibernating
[Up] [Print Copy]
  [Question]   Re: [CListCtrl] Rắc rối khi select một Item or Row - VC8 (MFC) 27/05/2008 11:49:11 (+0700) | #10 | 132981
Z0diac
Member

[Minus]    0    [Plus]
Joined: 25/04/2008 02:49:37
Messages: 21
Offline
[Profile] [PM]
Dạ anh. Và em cũng đã biết cách giải quyết vấn đề của em rồi ah. Cảm ơn anh đã trả lời.
[Up] [Print Copy]
[digg] [delicious] [google] [yahoo] [technorati] [reddit] [stumbleupon]
Go to: 
 Users currently in here 
1 Anonymous

Powered by JForum - Extended by HVAOnline
 hvaonline.net  |  hvaforum.net  |  hvazone.net  |  hvanews.net  |  vnhacker.org
1999 - 2013 © v2012|0504|218|