ComboListCtrl.cpp
上传用户:htjk88
上传日期:2010-03-27
资源大小:29k
文件大小:12k
源码类别:

ListView/ListBox

开发平台:

Visual C++

  1. /*******************************************************************************
  2. Author : Aravindan Premkumar
  3. Unregistered Copyright 2003 : Aravindan Premkumar
  4. All Rights Reserved
  5. This piece of code does not have any registered copyright and is free to be 
  6. used as necessary. The user is free to modify as per the requirements. As a
  7. fellow developer, all that I expect and request for is to be given the 
  8. credit for intially developing this reusable code by not removing my name as 
  9. the author.
  10. *******************************************************************************/
  11. #include "stdafx.h"
  12. #include "ComboListCtrl.h"
  13. #include "InPlaceCombo.h"
  14. #include "InPlaceEdit.h"
  15. #ifdef _DEBUG
  16. #define new DEBUG_NEW
  17. #undef THIS_FILE
  18. static char THIS_FILE[] = __FILE__;
  19. #endif
  20. //#defines
  21. #define FIRST_COLUMN 0
  22. #define MIN_COLUMN_WIDTH 10
  23. #define MAX_DROP_DOWN_ITEM_COUNT 10
  24. /////////////////////////////////////////////////////////////////////////////
  25. // CComboListCtrl
  26. CComboListCtrl::CComboListCtrl()
  27. {
  28. m_iColumnCounts = 0;
  29. m_ComboSupportColumnsList.RemoveAll();
  30. m_ReadOnlyColumnsList.RemoveAll();
  31. m_strValidEditCtrlChars.Empty();
  32. m_dwEditCtrlStyle = ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_LEFT | ES_NOHIDESEL;
  33. m_dwDropDownCtrlStyle = WS_BORDER | WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | ES_AUTOVSCROLL | 
  34. CBS_DROPDOWNLIST | CBS_DISABLENOSCROLL;
  35. }
  36. CComboListCtrl::~CComboListCtrl()
  37. {
  38. CInPlaceCombo::DeleteInstance();
  39. CInPlaceEdit::DeleteInstance();  
  40. }
  41. BEGIN_MESSAGE_MAP(CComboListCtrl, CListCtrl)
  42. //{{AFX_MSG_MAP(CComboListCtrl)
  43. ON_WM_HSCROLL()
  44. ON_WM_VSCROLL()
  45. ON_WM_LBUTTONDOWN()
  46. ON_NOTIFY_REFLECT(LVN_ENDLABELEDIT, OnEndLabelEdit)
  47. ON_NOTIFY_REFLECT(LVN_BEGINLABELEDIT, OnBeginLabelEdit)
  48. //}}AFX_MSG_MAP
  49. END_MESSAGE_MAP()
  50. /////////////////////////////////////////////////////////////////////////////
  51. // CComboListCtrl message handlers
  52. CInPlaceCombo* CComboListCtrl::ShowInPlaceList(int iRowIndex, int iColumnIndex, CStringList& rComboItemsList, 
  53.    CString strCurSelecetion /*= ""*/, int iSel /*= -1*/)
  54. {
  55. // The returned obPointer should not be saved
  56. // Make sure that the item is visible
  57. if (!EnsureVisible(iRowIndex, TRUE))
  58. {
  59. return NULL;
  60. }
  61. // Make sure that iColumnIndex is valid 
  62. CHeaderCtrl* pHeader = static_cast<CHeaderCtrl*> (GetDlgItem(FIRST_COLUMN));
  63. int iColumnCount = pHeader->GetItemCount();
  64. if (iColumnIndex >= iColumnCount || GetColumnWidth(iColumnIndex) < MIN_COLUMN_WIDTH) 
  65. {
  66. return NULL;
  67. }
  68. // Calculate the rectangle specifications for the combo box
  69. CRect obCellRect(0, 0, 0, 0);
  70. CalculateCellRect(iColumnIndex, iRowIndex, obCellRect);
  71. int iHeight = obCellRect.Height();  
  72. int iCount = (int )rComboItemsList.GetCount();
  73. iCount = (iCount < MAX_DROP_DOWN_ITEM_COUNT) ? 
  74. iCount + MAX_DROP_DOWN_ITEM_COUNT : (MAX_DROP_DOWN_ITEM_COUNT + 1); 
  75. obCellRect.bottom += iHeight * iCount; 
  76. // Create the in place combobox
  77. CInPlaceCombo* pInPlaceCombo = CInPlaceCombo::GetInstance();
  78. pInPlaceCombo->ShowComboCtrl(m_dwDropDownCtrlStyle, obCellRect, this, 0, iRowIndex, iColumnIndex, &rComboItemsList, 
  79.  strCurSelecetion, iSel);
  80. return pInPlaceCombo;
  81. }
  82. CInPlaceEdit* CComboListCtrl::ShowInPlaceEdit(int iRowIndex, int iColumnIndex, CString& rstrCurSelection)
  83. {
  84. // Create an in-place edit control
  85. CInPlaceEdit* pInPlaceEdit = CInPlaceEdit::GetInstance();
  86. CRect obCellRect(0, 0, 0, 0);
  87. CalculateCellRect(iColumnIndex, iRowIndex, obCellRect);
  88. pInPlaceEdit->ShowEditCtrl(m_dwEditCtrlStyle, obCellRect, this, 0, 
  89.    iRowIndex, iColumnIndex,
  90.    m_strValidChars[iColumnIndex], rstrCurSelection);
  91. return pInPlaceEdit;
  92. }
  93. void CComboListCtrl::OnHScroll(UINT iSBCode, UINT iPos, CScrollBar* pScrollBar) 
  94. {
  95. // TODO: Add your message handler code here and/or call default
  96. if (GetFocus() != this)
  97. {
  98. SetFocus();
  99. }
  100. CListCtrl::OnHScroll(iSBCode, iPos, pScrollBar);
  101. }
  102. void CComboListCtrl::OnVScroll(UINT iSBCode, UINT iPos, CScrollBar* pScrollBar) 
  103. {
  104. // TODO: Add your message handler code here and/or call default
  105. if (GetFocus() != this)
  106. {
  107. SetFocus();
  108. }
  109. CListCtrl::OnVScroll(iSBCode, iPos, pScrollBar);
  110. }
  111. void CComboListCtrl::OnLButtonDown(UINT iFlags, CPoint obPoint) 
  112. {
  113. // TODO: Add your message handler code here and/or call default
  114. int iColumnIndex = -1;
  115. int iRowIndex = -1;
  116. // Get the current column and row
  117. if (!HitTestEx(obPoint, &iRowIndex, &iColumnIndex))
  118. {
  119. return;
  120. }
  121. CListCtrl::OnLButtonDown(iFlags, obPoint);
  122. // If column is not read only then
  123. // If the SHIFT or CTRL key is down call the base class
  124. // Check the high bit of GetKeyState to determine whether SHIFT or CTRL key is down
  125. if ((GetKeyState(VK_SHIFT) & 0x80) || (GetKeyState(VK_CONTROL) & 0x80))
  126. {
  127. return;
  128. }
  129. // Get the current selection before creating the in place combo box
  130. CString strCurSelection = GetItemText(iRowIndex, iColumnIndex);
  131. if (-1 != iRowIndex)
  132. {
  133. UINT flag = LVIS_FOCUSED;
  134. if ((GetItemState(iRowIndex, flag ) & flag) == flag)
  135. {
  136. // Add check for LVS_EDITLABELS
  137. if (GetWindowLong(m_hWnd, GWL_STYLE) & LVS_EDITLABELS)
  138. {
  139. // If combo box is supported
  140. // Create and show the in place combo box
  141. if (IsCombo(iColumnIndex))
  142. {
  143. CStringList obComboItemsList;
  144. GetParent()->SendMessage(WM_SET_ITEMS, (WPARAM)iColumnIndex, (LPARAM)&obComboItemsList);  
  145. CInPlaceCombo* pInPlaceComboBox = ShowInPlaceList(iRowIndex, iColumnIndex, obComboItemsList, strCurSelection);
  146. ASSERT(pInPlaceComboBox); 
  147. // Set the selection to previous selection
  148. pInPlaceComboBox->SelectString(-1, strCurSelection);
  149. }
  150. // If combo box is not read only
  151. // Create and show the in place edit control
  152. else if (!IsReadOnly(iColumnIndex))
  153. {
  154. CInPlaceEdit* pInPlaceEdit = ShowInPlaceEdit(iRowIndex, iColumnIndex, strCurSelection);
  155. }
  156. }
  157. }
  158. }  
  159. }
  160. bool CComboListCtrl::HitTestEx(CPoint &obPoint, int* pRowIndex, int* pColumnIndex) const
  161. {
  162. if (!pRowIndex || !pColumnIndex)
  163. {
  164. return false;
  165. }
  166. // Get the row index
  167. *pRowIndex = HitTest(obPoint, NULL);
  168. if (pColumnIndex)
  169. {
  170. *pColumnIndex = 0;
  171. }
  172. // Make sure that the ListView is in LVS_REPORT
  173. if ((GetWindowLong(m_hWnd, GWL_STYLE) & LVS_TYPEMASK) != LVS_REPORT)
  174. {
  175. return false;
  176. }
  177. // Get the number of columns
  178. CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
  179. int iColumnCount = pHeader->GetItemCount();
  180. // Get bounding rect of item and check whether obPoint falls in it.
  181. CRect obCellRect;
  182. GetItemRect(*pRowIndex, &obCellRect, LVIR_BOUNDS);
  183. if (obCellRect.PtInRect(obPoint))
  184. {
  185. // Now find the column
  186. for (*pColumnIndex = 0; *pColumnIndex < iColumnCount; (*pColumnIndex)++)
  187. {
  188. int iColWidth = GetColumnWidth(*pColumnIndex);
  189. if (obPoint.x >= obCellRect.left && obPoint.x <= (obCellRect.left + iColWidth))
  190. {
  191. return true;
  192. }
  193. obCellRect.left += iColWidth;
  194. }
  195. }
  196. return false;
  197. }
  198. void CComboListCtrl::SetComboColumns(int iColumnIndex, bool bSet /*= true*/)
  199. {
  200. // If the Column Index is not present && Set flag is false
  201. // Then do nothing 
  202. // If the Column Index is present && Set flag is true
  203. // Then do nothing
  204. POSITION Pos = m_ComboSupportColumnsList.Find(iColumnIndex);
  205. // If the Column Index is not present && Set flag is true
  206. // Then Add to list
  207. if ((NULL == Pos) && bSet) 
  208. {
  209. m_ComboSupportColumnsList.AddTail(iColumnIndex); 
  210. }
  211. // If the Column Index is present && Set flag is false
  212. // Then Remove from list
  213. if ((NULL != Pos) && !bSet) 
  214. {
  215. m_ComboSupportColumnsList.RemoveAt(Pos); 
  216. }
  217. }
  218. void CComboListCtrl::SetReadOnlyColumns(int iColumnIndex, bool bSet /*= true*/)
  219. {
  220. // If the Column Index is not present && Set flag is false
  221. // Then do nothing 
  222. // If the Column Index is present && Set flag is true
  223. // Then do nothing
  224. POSITION Pos = m_ReadOnlyColumnsList.Find(iColumnIndex);
  225. // If the Column Index is not present && Set flag is true
  226. // Then Add to list
  227. if ((NULL == Pos) && bSet) 
  228. {
  229. m_ReadOnlyColumnsList.AddTail(iColumnIndex); 
  230. }
  231. // If the Column Index is present && Set flag is false
  232. // Then Remove from list
  233. if ((NULL != Pos) && !bSet) 
  234. {
  235. m_ReadOnlyColumnsList.RemoveAt(Pos); 
  236. }
  237. }
  238. bool CComboListCtrl::IsReadOnly(int iColumnIndex)
  239. {
  240. if (m_ReadOnlyColumnsList.Find(iColumnIndex))
  241. {
  242. return true;
  243. }
  244. return false;
  245. }
  246. bool CComboListCtrl::IsCombo(int iColumnIndex)
  247. {
  248. if (m_ComboSupportColumnsList.Find(iColumnIndex))
  249. {
  250. return true;
  251. }
  252. return false;
  253. }
  254. void CComboListCtrl::CalculateCellRect(int iColumnIndex, int iRowIndex, CRect& robCellRect)
  255. {
  256. GetItemRect(iRowIndex, &robCellRect, LVIR_BOUNDS);
  257. CRect rcClient;
  258. GetClientRect(&rcClient);
  259. if (robCellRect.right > rcClient.right) 
  260. {
  261. robCellRect.right = rcClient.right;
  262. }
  263. ScrollToView(iColumnIndex, robCellRect); 
  264. }
  265. void CComboListCtrl::OnEndLabelEdit(NMHDR* pNMHDR, LRESULT* pResult) 
  266. {
  267. LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR;
  268. // TODO: Add your control notification handler code here
  269. // Update the item text with the new text
  270. SetItemText(pDispInfo->item.iItem, pDispInfo->item.iSubItem, pDispInfo->item.pszText);
  271. GetParent()->SendMessage(WM_VALIDATE, GetDlgCtrlID(), (LPARAM)pDispInfo); 
  272. *pResult = 0;
  273. }
  274. void CComboListCtrl::SetValidEditCtrlCharacters(CString &rstrValidCharacters)
  275. {
  276. m_strValidEditCtrlChars = rstrValidCharacters;
  277. }
  278. void CComboListCtrl::SetColumnValidEditCtrlCharacters(CString &rstrValidCharacters,int column)
  279. {
  280. if(column>MAX_LISTCTRL_COLUMNS-1)
  281. return;
  282. if(column == -1)
  283. {
  284. for(int i=0;i<MAX_LISTCTRL_COLUMNS;i++)
  285. {
  286. m_strValidChars[i] = rstrValidCharacters;
  287. }
  288. }
  289. else
  290. m_strValidChars[column] = rstrValidCharacters;
  291. }
  292. void CComboListCtrl::EnableHScroll(bool bEnable /*= true*/)
  293. {
  294. if (bEnable)
  295. {
  296. m_dwDropDownCtrlStyle |= WS_HSCROLL;
  297. }
  298. else
  299. {
  300. m_dwDropDownCtrlStyle &= ~WS_HSCROLL;
  301. }
  302. }
  303. void CComboListCtrl::EnableVScroll(bool bEnable /*= true*/)
  304. {
  305. if (bEnable)
  306. {
  307. m_dwDropDownCtrlStyle |= WS_VSCROLL;
  308. }
  309. else
  310. {
  311. m_dwDropDownCtrlStyle &= ~WS_VSCROLL;
  312. }
  313. }
  314. void CComboListCtrl::ScrollToView(int iColumnIndex, /*int iOffSet, */CRect& robCellRect)
  315. {
  316. // Now scroll if we need to expose the column
  317. CRect rcClient;
  318. GetClientRect(&rcClient);
  319. int iColumnWidth = GetColumnWidth(iColumnIndex);
  320. // Get the column iOffset
  321. int iOffSet = 0;
  322. for (int iIndex_ = 0; iIndex_ < iColumnIndex; iIndex_++)
  323. {
  324. iOffSet += GetColumnWidth(iIndex_);
  325. }
  326. // If x1 of cell rect is < x1 of ctrl rect or
  327. // If x1 of cell rect is > x1 of ctrl rect or **Should not ideally happen**
  328. // If the width of the cell extends beyond x2 of ctrl rect then
  329. // Scroll
  330. CSize obScrollSize(0, 0);
  331. if (((iOffSet + robCellRect.left) < rcClient.left) || 
  332. ((iOffSet + robCellRect.left) > rcClient.right))
  333. {
  334. obScrollSize.cx = iOffSet + robCellRect.left;
  335. }
  336. else if ((iOffSet + robCellRect.left + iColumnWidth) > rcClient.right)
  337. {
  338. obScrollSize.cx = iOffSet + robCellRect.left + iColumnWidth - rcClient.right;
  339. }
  340. Scroll(obScrollSize);
  341. robCellRect.left -= obScrollSize.cx;
  342. // Set the width to the column width
  343. robCellRect.left += iOffSet;
  344. robCellRect.right = robCellRect.left + iColumnWidth;
  345. }
  346. void CComboListCtrl::OnBeginLabelEdit(NMHDR* pNMHDR, LRESULT* pResult) 
  347. {
  348. LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR;
  349. // TODO: Add your control notification handler code here
  350. if (IsReadOnly(pDispInfo->item.iSubItem))
  351. {
  352. *pResult = 1;
  353. return;
  354. }
  355. *pResult = 0;
  356. }
  357. int CComboListCtrl::InsertColumn(int nCol,LPCTSTR lpszColumnHeading,int nFormat ,int nWidth,int nSubItem)
  358. {
  359. m_iColumnCounts++;
  360. return CListCtrl::InsertColumn( nCol, lpszColumnHeading, nFormat, nWidth, nSubItem);
  361. }
  362. int CComboListCtrl::GetColumnCounts()
  363. {
  364. return m_iColumnCounts;
  365. }
  366. void CComboListCtrl::DeleteAllColumn()
  367. {
  368. for(int i=0;i<m_iColumnCounts;i++)
  369. {
  370. DeleteColumn(0);
  371. }
  372. }