PropertyGridItemFlagBits.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. #include "stdafx.h"
  2. #include "PropertyGridInplaceEdit.h"
  3. #include "PropertyGridInplaceButton.h"
  4. #include "PropertyGridInplaceList.h"
  5. #include "PropertyGridItem.h"
  6. #include "PropertyGridItemFlagBits.h"
  7. #include "PropertyGrid_DrawHelpers.h"
  8. // 标志位的分隔符
  9. const TCHAR FLAG_BITS_SEPARATOR = _T('|');
  10. /////////////////////////////////////////////////////////////////////////////
  11. // CPropertyGridInplaceCheckList
  12. /////////////////////////////////////////////////////////////////////////////
  13. CPropertyGridInplaceCheckList::CPropertyGridInplaceCheckList()
  14. : m_pItem(0)
  15. {
  16. }
  17. CPropertyGridInplaceCheckList::~CPropertyGridInplaceCheckList()
  18. {
  19. }
  20. BEGIN_MESSAGE_MAP(CPropertyGridInplaceCheckList, CCheckListBox)
  21. //{{AFX_MSG_MAP(CPropertyGridInplaceCheckList)
  22. ON_WM_KEYDOWN()
  23. ON_WM_KILLFOCUS()
  24. ON_WM_MOUSEACTIVATE()
  25. //}}AFX_MSG_MAP
  26. END_MESSAGE_MAP()
  27. void CPropertyGridInplaceCheckList::Create(CPropertyGridItem* pItem, CRect rect, BOOL checkStates[])
  28. {
  29. ASSERT(pItem && pItem->GetGrid());
  30. m_pItem = pItem;
  31. m_bCanceled = FALSE;
  32. CRect rcValue = m_pItem->GetValueRect();
  33. CWnd* pParent = m_pItem->GetGrid();
  34. if (!m_hWnd)
  35. {
  36. CCheckListBox::Create(WS_CHILD | WS_BORDER | WS_VSCROLL | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS, CRect(0, 0, 0, 0), pParent, 0);
  37. SetOwner(pParent);
  38. SetFont(pParent->GetFont());
  39. }
  40. ResetContent();
  41. CPGItemConstraints* pList = m_pItem->GetConstraints();
  42. POSITION pos = pList->GetHeadPosition();
  43. int dx = rect.right - rcValue.left;
  44. CWindowDC dc(pParent);
  45. CPGFontDC font(&dc, pParent->GetFont());
  46. int nThumbLength = GetSystemMetrics(SM_CXHTHUMB);
  47. while (pos)
  48. {
  49. CString str = pList->GetNext(pos);
  50. int index = AddString(str);
  51. SetCheck(index, checkStates[index]);
  52. dx = __max(dx, dc.GetTextExtent(str).cx + nThumbLength * 2);
  53. }
  54. int nHeight = GetItemHeight(0);
  55. rect.top = rect.bottom;
  56. rect.bottom += nHeight * __min(10, GetCount()) + 2;
  57. rect.left = rect.right - __min(dx, rect.Width() - PGI_EXPAND_BORDER);
  58. pParent->ClientToScreen(&rect);
  59. // 根据系统的工作区调整列表框位置
  60. CRect rcWork;
  61. ::SystemParametersInfo(SPI_GETWORKAREA, NULL, &rcWork, 0);
  62. if (rect.bottom > rcWork.bottom) rect.OffsetRect(0, - rect.Height() - rcValue.Height() - 3);
  63. if (rect.top < rcWork.top) rect.OffsetRect(0, rcWork.top - rect.top);
  64. if (rect.left < rcWork.left) rect.OffsetRect(rcWork.left - rect.left, 0);
  65. if (rect.right > rcWork.right) rect.OffsetRect(rcWork.right - rect.right, 0);
  66. // 以子窗口方式创建内置列表框,然后再执行下面这段代码,内置列表
  67. // 框将以弹出窗口方式显示,并得到输入焦点,但当前窗口保持不变
  68. SetFocus();
  69. ::SetWindowLong(m_hWnd, GWL_HWNDPARENT, NULL);
  70. ModifyStyle(WS_CHILD, WS_POPUP);
  71. ::SetWindowLong(m_hWnd, GWL_HWNDPARENT, (LONG)pParent->m_hWnd);
  72. SetWindowPos(0, rect.left, rect.top, rect.Width(), rect.Height(), SWP_NOZORDER|SWP_SHOWWINDOW|SWP_NOACTIVATE);
  73. CPGMouseMonitor::SetupHook(this);
  74. }
  75. void CPropertyGridInplaceCheckList::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
  76. {
  77. if (nChar == VK_ESCAPE)
  78. {
  79. m_bCanceled = TRUE;
  80. GetOwner()->SetFocus();
  81. }
  82. CCheckListBox::OnKeyDown(nChar, nRepCnt, nFlags);
  83. }
  84. void CPropertyGridInplaceCheckList::OnKillFocus(CWnd* pNewWnd)
  85. {
  86. CCheckListBox::OnKillFocus(pNewWnd);
  87. if (!m_bCanceled)
  88. Apply();
  89. CPGMouseMonitor::SetupHook(NULL);
  90. DestroyItem();
  91. }
  92. int CPropertyGridInplaceCheckList::OnMouseActivate(CWnd* pDesktopWnd, UINT nHitTest, UINT message)
  93. {
  94. // 用鼠标点击内置复选列表框时,不改变当前窗口
  95. return MA_NOACTIVATE;
  96. }
  97. void CPropertyGridInplaceCheckList::Apply()
  98. {
  99. CString strNewValue;
  100. CPGItemConstraints* pList = m_pItem->GetConstraints();
  101. for (int index = 0; index < GetCount(); index++)
  102. {
  103. if ( GetCheck(index) )
  104. {
  105. POSITION pos = pList->FindIndex(index);
  106. CString text = pList->GetAt(pos);
  107. if (strNewValue.IsEmpty())
  108. strNewValue = text;
  109. else
  110. strNewValue += FLAG_BITS_SEPARATOR + text;
  111. }
  112. }
  113. if (strNewValue != m_pItem->GetValue())
  114. m_pItem->OnValueChanged(strNewValue);
  115. }
  116. void CPropertyGridInplaceCheckList::DestroyItem()
  117. {
  118. m_pItem = NULL;
  119. DestroyWindow( );
  120. }
  121. /////////////////////////////////////////////////////////////////////////////
  122. // CPropertyGridItemFlagBits
  123. /////////////////////////////////////////////////////////////////////////////
  124. CPropertyGridItemFlagBits::CPropertyGridItemFlagBits(CString strCaption)
  125. : CPropertyGridItem(strCaption)
  126. {
  127. _Init();
  128. }
  129. CPropertyGridItemFlagBits::CPropertyGridItemFlagBits(UINT nID)
  130. : CPropertyGridItem(nID)
  131. {
  132. _Init();
  133. }
  134. CPropertyGridItemFlagBits::~CPropertyGridItemFlagBits()
  135. {
  136. }
  137. void CPropertyGridItemFlagBits::_Init()
  138. {
  139. SetFlags(pgitemHasComboButton); // 设置属性项不可编辑、有下拉按钮
  140. m_dwValue = 0;
  141. m_pBindFlagBits = NULL;
  142. }
  143. void CPropertyGridItemFlagBits::AddFlagItem(int nItemValue, CString nItemText)
  144. {
  145. ASSERT( nItemText.GetLength() ); // 不能为空
  146. ASSERT( nItemText.Find(FLAG_BITS_SEPARATOR) == -1 ); // 不能包含分隔符
  147. m_lstFlagItemValues.Add(nItemValue);
  148. GetConstraints()->AddConstraint(nItemText);
  149. }
  150. void CPropertyGridItemFlagBits::SetFlagBits(DWORD value)
  151. {
  152. int count = (int)m_lstFlagItemValues.GetSize();
  153. ASSERT(count); // 设置属性值时,必须存在标志位数据项
  154. m_dwValue = value;
  155. CString strValue;
  156. for (int index = 0; index < count; index++)
  157. {
  158. if (m_dwValue & m_lstFlagItemValues[index])
  159. {
  160. POSITION pos = GetConstraints()->FindIndex(index);
  161. CString text = GetConstraints()->GetAt(pos);
  162. if (strValue.IsEmpty())
  163. strValue = text;
  164. else
  165. strValue += FLAG_BITS_SEPARATOR + text;
  166. }
  167. }
  168. CPropertyGridItem::SetValue(strValue);
  169. if (m_pBindFlagBits)
  170. *m_pBindFlagBits = m_dwValue;
  171. }
  172. DWORD CPropertyGridItemFlagBits::GetFlagBits()
  173. {
  174. int count = (int)m_lstFlagItemValues.GetSize();
  175. ASSERT(count); // 获取属性值时,必须存在标志位数据项
  176. return m_dwValue;
  177. }
  178. void CPropertyGridItemFlagBits::BindToFlagBits(DWORD* pBindFlagBits)
  179. {
  180. m_pBindFlagBits = pBindFlagBits;
  181. if (m_pBindFlagBits)
  182. SetFlagBits(*m_pBindFlagBits);
  183. }
  184. void CPropertyGridItemFlagBits::SetValue(CString strValue)
  185. {
  186. int count = (int)m_lstFlagItemValues.GetSize();
  187. ASSERT(count);
  188. CStringList lstValue;
  189. SplitString(strValue, FLAG_BITS_SEPARATOR, lstValue);
  190. // 计算标志位
  191. DWORD dwValue = 0;
  192. for (int index = 0; index < count; index++)
  193. {
  194. POSITION pos = GetConstraints()->FindIndex(index);
  195. CString text = GetConstraints()->GetAt(pos);
  196. if ( lstValue.Find(text) )
  197. dwValue |= m_lstFlagItemValues[index];
  198. }
  199. SetFlagBits(dwValue);
  200. }
  201. void CPropertyGridItemFlagBits::OnInplaceButtonDown()
  202. {
  203. int count = (int)m_lstFlagItemValues.GetSize();
  204. ASSERT(count); // 设置属性值时,必须存在标志位数据项
  205. BOOL* checkStates = new BOOL [count];
  206. for (int index = 0; index < count; index++)
  207. {
  208. if (m_dwValue & m_lstFlagItemValues[index])
  209. checkStates[index] = TRUE;
  210. else
  211. checkStates[index] = FALSE;
  212. }
  213. m_wndCheckList.Create(this, GetItemRect(), checkStates);
  214. delete [] checkStates;
  215. }
  216. void CPropertyGridItemFlagBits::OnLButtonDblClk()
  217. {
  218. // 如果不覆写该函数,双击会导致列表项轮流成为属性值
  219. }
  220. void CPropertyGridItemFlagBits::SplitString(CString str, TCHAR separator, CStringList& splittedStrings)
  221. {
  222. CString tempStr = str;
  223. int index;
  224. while ((index = tempStr.Find(separator)) != -1)
  225. {
  226. splittedStrings.AddTail( tempStr.Left(index) );
  227. tempStr = tempStr.Mid(index + 1);
  228. }
  229. splittedStrings.AddTail( tempStr );
  230. }