ListCombo.h
上传用户:sztopon
上传日期:2014-01-21
资源大小:55k
文件大小:12k
源码类别:

ListView/ListBox

开发平台:

Visual C++

  1. #pragma once
  2. #include <atltheme.h>
  3. #include "ListTypes.h"
  4. class CListCombo : public CWindowImpl< CListCombo, CComboBox >
  5. {
  6. public:
  7. CListCombo() : m_wndEditCtrl( this, 1 )
  8. {
  9. m_nItem = NULL_ITEM;
  10. m_nSubItem = NULL_SUBITEM;
  11. m_nFlags = ITEM_FLAGS_NONE;
  12. m_nExitChar = 0;
  13. m_bMouseOver = FALSE;
  14. m_bActivate = FALSE;
  15. m_bShowThemed = TRUE;
  16. }
  17. ~CListCombo()
  18. {
  19. }
  20. protected:
  21. int m_nItem;
  22. int m_nSubItem;
  23. UINT m_nFlags;
  24. TCHAR m_nExitChar;
  25. BOOL m_bShowThemed;
  26. BOOL m_bMouseOver;
  27. BOOL m_bActivate;
  28. BOOL m_bSwappedButtons;
  29. CRect m_rcStatic;
  30. CRect m_rcButton;
  31. COLORREF m_rgbStaticBackground;
  32. COLORREF m_rgbStaticText;
  33. CTheme m_thmCombo;
  34. CFont m_fntComboFont;
  35. CContainedWindowT< CEdit > m_wndEditCtrl;
  36. public:
  37. BOOL Create( HWND hWndParent, int nItem, int nSubItem, CRect& rcRect, UINT nFlags, LPCTSTR lpszItemText, BOOL bShowThemed, CListArray < CString >& aComboList )
  38. {
  39. m_nItem = nItem;
  40. m_nSubItem = nSubItem;
  41. m_nFlags = nFlags;
  42. m_nExitChar = 0;
  43. m_bActivate = FALSE;
  44. m_bShowThemed = bShowThemed;
  45. m_bSwappedButtons = GetSystemMetrics( SM_SWAPBUTTON );
  46. m_rgbStaticBackground = GetSysColor( COLOR_HIGHLIGHT );
  47. m_rgbStaticText = GetSysColor( COLOR_HIGHLIGHTTEXT );
  48. // destroy old combo control...
  49. if ( IsWindow() )
  50. DestroyWindow();
  51. DWORD dwStyle = WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | CBS_AUTOHSCROLL | CBS_SORT;
  52. if ( nFlags & ITEM_FLAGS_COMBO_EDIT )
  53. dwStyle |= CBS_DROPDOWN;
  54. else
  55. dwStyle |= CBS_DROPDOWNLIST;
  56. if ( nFlags & ITEM_FLAGS_EDIT_UPPER )
  57. dwStyle |= CBS_UPPERCASE;
  58. // create combo control
  59. if ( CWindowImpl< CListCombo, CComboBox >::Create( hWndParent, CRect( ( ( dwStyle & CBS_DROPDOWNLIST ) == CBS_DROPDOWNLIST ) ? rcRect.left + 3 : rcRect.left + 1, rcRect.top, rcRect.right, rcRect.bottom + ( 6 * rcRect.Height() ) ), NULL, dwStyle ) == NULL )
  60. return FALSE;
  61. // open combo theme
  62. if ( m_thmCombo.IsThemeNull() )
  63. m_thmCombo.OpenThemeData( m_hWnd, L"COMBOBOX" );
  64. // get system message font
  65. CLogFont logFont;
  66. logFont.SetMessageBoxFont();
  67. if ( !m_fntComboFont.IsNull() )
  68. m_fntComboFont.DeleteObject();
  69. if ( m_fntComboFont.CreateFontIndirect( &logFont ) == NULL )
  70. return FALSE;
  71. SetFont( m_fntComboFont, FALSE );
  72. // subclass edit control to capture keyboard input
  73. HWND hEditControl = GetWindow( GW_CHILD );
  74. if ( hEditControl != NULL )
  75. m_wndEditCtrl.SubclassWindow( hEditControl );
  76. for ( int nComboItem = 0; nComboItem < aComboList.GetSize(); nComboItem++ )
  77. AddString( aComboList[ nComboItem ] );
  78. if ( ( dwStyle & CBS_DROPDOWNLIST ) == CBS_DROPDOWNLIST )
  79. {
  80. int nIndex = FindStringExact( -1, lpszItemText );
  81. if ( nIndex != CB_ERR )
  82. SetCurSel( nIndex );
  83. }
  84. else
  85. {
  86. SetWindowText( lpszItemText );
  87. SetEditSel( 0, -1 );
  88. }
  89. // set static edit height
  90. SetItemHeight( -1, rcRect.Height() - 6 );
  91. COMBOBOXINFO infoComboBox = { sizeof( COMBOBOXINFO ) };
  92. if ( !::GetComboBoxInfo( m_hWnd, &infoComboBox ) )
  93. return FALSE;
  94. // store combobox details for painting
  95. m_rcStatic = infoComboBox.rcItem;
  96. m_rcButton = infoComboBox.rcButton;
  97. m_rcButton.DeflateRect( 0, 1 );
  98. m_rcButton.OffsetRect( -2, 0 );
  99. // show combo control
  100. ShowWindow( SW_SHOW );
  101. SetFocus();
  102. // force redraw now
  103. RedrawWindow();
  104. return TRUE;
  105. }
  106. BOOL IsValid( TCHAR nChar )
  107. {
  108. // validate number and float input
  109. if ( !( m_nFlags & ( ITEM_FLAGS_EDIT_NUMBER | ITEM_FLAGS_EDIT_FLOAT ) ) || nChar == VK_BACK )
  110. return TRUE;
  111. CString strValue;
  112. int nValueLength = GetWindowTextLength() + 1;
  113. GetWindowText( strValue.GetBuffer( nValueLength ), nValueLength );
  114. strValue.ReleaseBuffer();
  115. // get selected positions
  116. DWORD dwSelection = GetEditSel();
  117. int nStartChar = LOWORD( dwSelection );
  118. int nEndChar = HIWORD( dwSelection );
  119. // are we changing the sign?
  120. if ( ( m_nFlags & ITEM_FLAGS_EDIT_NEGATIVE ) && nChar == _T( '-' ) )
  121. {
  122. BOOL bNegative = FALSE;
  123. if ( m_nFlags & ITEM_FLAGS_EDIT_FLOAT )
  124. {
  125. double dblValue = _tstof( strValue );
  126. bNegative = ( dblValue < 0 );
  127. strValue.Format( _T( "%lf" ), -dblValue );
  128. }
  129. else
  130. {
  131. long lValue = _ttol( strValue );
  132. bNegative = ( lValue < 0 );
  133. strValue.Format( _T( "%ld" ), -lValue );
  134. }
  135. SetWindowText( strValue );
  136. // restore select position
  137. SetEditSel( bNegative ? nStartChar - 1 : nStartChar + 1, bNegative ? nEndChar - 1 : nEndChar + 1 );
  138. return FALSE;
  139. }
  140. // construct new value string using entered character
  141. CString strNewValue = strValue.Left( nStartChar ) + nChar + strValue.Right( strValue.GetLength() - nEndChar );
  142. int nGreaterThan = 0;
  143. int nLessThan = 0;
  144. int nEquals = 0;
  145. int nDecimalPoint = 0;
  146. int nNegativeIndex = -1;
  147. int nGreaterIndex = -1;
  148. int nLessIndex = -1;
  149. int nEqualIndex = -1;
  150. int nDecimalIndex = -1;
  151. int nDigitIndex = -1;
  152. for ( int nCharIndex = 0; nCharIndex < strNewValue.GetLength(); nCharIndex++ )
  153. {
  154. TCHAR nCharValue = strNewValue[ nCharIndex ];
  155. switch ( nCharValue )
  156. {
  157. case _T( '-' ): nNegativeIndex = nCharIndex;
  158. break;
  159. case _T( '>' ): if ( !( m_nFlags & ITEM_FLAGS_EDIT_OPERATOR ) )
  160. return FALSE;
  161. nGreaterIndex = nCharIndex;
  162. nGreaterThan++;
  163. break;
  164. case _T( '<' ): if ( !( m_nFlags & ITEM_FLAGS_EDIT_OPERATOR ) )
  165. return FALSE;
  166. nLessIndex = nCharIndex;
  167. nLessThan++;
  168. break;
  169. case _T( '=' ): if ( !( m_nFlags & ITEM_FLAGS_EDIT_OPERATOR ) )
  170. return FALSE;
  171. nEqualIndex = nCharIndex;
  172. nEquals++;
  173. break;
  174. case _T( '.' ): if ( !( m_nFlags & ITEM_FLAGS_EDIT_FLOAT ) )
  175. return FALSE;
  176. nDecimalIndex = nCharIndex;
  177. nDecimalPoint++;
  178. break;
  179. default: if ( !_istdigit( nCharValue ) )
  180. return FALSE;
  181. if ( nDigitIndex < 0 )
  182. nDigitIndex = nCharIndex;
  183. break;
  184. }
  185. // invalid if text contains more than one '>', '<', '=' or '.'
  186. if ( nGreaterThan > 1 || nLessThan > 1 || nEquals > 1 || nDecimalPoint > 1 )
  187. return FALSE;
  188. }
  189. // invalid if text contains '=>' or '=<'
  190. if ( nGreaterIndex != -1 && nEqualIndex != -1 && nGreaterIndex > nEqualIndex )
  191. return FALSE;
  192. if ( nLessIndex != -1 && nEqualIndex != -1 && nLessIndex > nEqualIndex )
  193. return FALSE;
  194. // invalid if digits exist before operator
  195. if ( nDigitIndex != -1 && nGreaterIndex != -1 && nGreaterIndex > nDigitIndex )
  196. return FALSE;
  197. if ( nDigitIndex != -1 && nLessIndex != -1 && nLessIndex > nDigitIndex )
  198. return FALSE;
  199. if ( nDigitIndex != -1 && nEqualIndex != -1 && nEqualIndex > nDigitIndex )
  200. return FALSE;
  201. if ( nDigitIndex != -1 && nNegativeIndex != -1 && nNegativeIndex > nDigitIndex )
  202. return FALSE;
  203. return TRUE;
  204. }
  205. BEGIN_MSG_MAP_EX(CListCombo)
  206. MESSAGE_RANGE_HANDLER_EX(WM_MOUSEFIRST,WM_MOUSELAST,OnMouseRange)
  207. MSG_WM_MOUSELEAVE(OnMouseLeave)
  208. MSG_WM_ERASEBKGND(OnEraseBkgnd)
  209. MSG_WM_PAINT(OnPaint)
  210. REFLECTED_COMMAND_CODE_HANDLER_EX(CBN_KILLFOCUS, OnKillFocus)
  211. MSG_WM_GETDLGCODE(OnGetDlgCode)
  212. MSG_WM_CHAR(OnChar)
  213. DEFAULT_REFLECTION_HANDLER()
  214. ALT_MSG_MAP(1)
  215. MSG_WM_GETDLGCODE(OnGetDlgCode)
  216. MSG_WM_CHAR(OnChar)
  217. END_MSG_MAP_EX()
  218. LRESULT OnMouseRange( UINT nMessage, WPARAM wParam, LPARAM lParam )
  219. {
  220. SetMsgHandled( FALSE );
  221. if ( nMessage == WM_MOUSEMOVE && !m_bMouseOver )
  222. {
  223. m_bMouseOver = TRUE;
  224. TRACKMOUSEEVENT trkMouse;
  225. trkMouse.cbSize = sizeof( TRACKMOUSEEVENT );
  226. trkMouse.dwFlags = TME_LEAVE;
  227. trkMouse.hwndTrack = m_hWnd;
  228. // notify when the mouse leaves button
  229. _TrackMouseEvent( &trkMouse );
  230. }
  231. // do not show button as pressed when first created
  232. m_bActivate = TRUE;
  233. InvalidateRect( m_rcButton );
  234. return 0;
  235. }
  236. void OnMouseLeave()
  237. {
  238. m_bMouseOver = FALSE;
  239. InvalidateRect( m_rcButton );
  240. }
  241. BOOL OnEraseBkgnd( CDCHandle dcErase ) 
  242. {
  243. return TRUE;
  244. }
  245. void OnPaint( HDC )
  246. {
  247. CPaintDC dcPaint( m_hWnd );
  248. CRect rcClient;
  249. GetClientRect( rcClient );
  250. CMemoryDC dcMemory( dcPaint.m_hDC, rcClient );
  251. CRect rcClip;
  252. if ( dcPaint.GetClipBox( rcClip ) == ERROR )
  253. return;
  254. int nContextState = dcMemory.SaveDC();
  255. // do not repaint background if drawing button only
  256. if ( !rcClip.EqualRect( m_rcButton ) )
  257. {
  258. CWindow wndParent( GetParent() );
  259. if ( wndParent.IsWindow() )
  260. {
  261. // draw background from parent
  262. CPoint ptOrigin( 0 );
  263. MapWindowPoints( wndParent, &ptOrigin, 1 );
  264. dcMemory.OffsetWindowOrg( ptOrigin.x, ptOrigin.y, &ptOrigin );
  265. wndParent.SendMessage( WM_PAINT, (WPARAM)dcMemory.m_hDC );
  266. dcMemory.SetWindowOrg( ptOrigin );
  267. }
  268. }
  269. DWORD dwPoint = GetMessagePos();
  270. CPoint ptMouse( GET_X_LPARAM( dwPoint ), GET_Y_LPARAM( dwPoint ) );
  271. ScreenToClient( &ptMouse );
  272. DWORD dwStyle = GetStyle();
  273. BOOL bHotButton = m_bActivate && ( ( ( dwStyle & CBS_DROPDOWNLIST ) == CBS_DROPDOWNLIST ) ? rcClient.PtInRect( ptMouse ) : m_rcButton.PtInRect( ptMouse ) );
  274. BOOL bPressed = bHotButton && ( GetAsyncKeyState( m_bSwappedButtons ? VK_RBUTTON : VK_LBUTTON ) < 0 );
  275. if ( ( dwStyle & CBS_DROPDOWNLIST ) == CBS_DROPDOWNLIST && !rcClip.EqualRect( m_rcButton ) )
  276. {
  277. dcMemory.SetBkColor( m_rgbStaticBackground );
  278. dcMemory.ExtTextOut( m_rcStatic.left, m_rcStatic.top, ETO_OPAQUE, m_rcStatic, _T( "" ), 0, NULL );
  279. // draw static text
  280. int nIndex = GetCurSel();
  281. if ( nIndex != CB_ERR )
  282. {
  283. CString strText;
  284. GetLBText( nIndex, strText );
  285. if ( !strText.IsEmpty() )
  286. {
  287. CRect rcText( m_rcStatic );
  288. rcText.OffsetRect( 1, 1 );
  289. dcMemory.SelectFont( m_fntComboFont );
  290. dcMemory.SetTextColor( m_rgbStaticText );
  291. dcMemory.SetBkMode( TRANSPARENT );
  292. dcMemory.DrawText( strText, strText.GetLength(), rcText, DT_LEFT | DT_SINGLELINE | DT_NOPREFIX | DT_VCENTER );
  293. }
  294. }
  295. }
  296. // draw drop down button
  297. if ( m_bShowThemed && !m_thmCombo.IsThemeNull() )
  298. m_thmCombo.DrawThemeBackground( dcMemory, CP_DROPDOWNBUTTON, bPressed ? CBXS_PRESSED : ( bHotButton ? CBXS_HOT : CBXS_NORMAL ), m_rcButton );
  299. else
  300. dcMemory.DrawFrameControl( m_rcButton, DFC_SCROLL, DFCS_SCROLLDOWN | ( bPressed ? DFCS_FLAT | DFCS_PUSHED : 0 ) );
  301. dcMemory.RestoreDC( nContextState );
  302. }
  303. void OnKillFocus( UINT uCode, int nCtrlID, HWND hwndCtrl )
  304. {
  305. SetMsgHandled( FALSE );
  306. CWindow wndParent( GetParent() );
  307. if ( wndParent.IsWindow() )
  308. {
  309. CString strValue;
  310. if ( ( GetStyle() & CBS_DROPDOWNLIST ) == CBS_DROPDOWNLIST )
  311. {
  312. int nIndex = GetCurSel();
  313. if ( nIndex != CB_ERR )
  314. GetLBText( nIndex, strValue );
  315. }
  316. else
  317. {
  318. int nValueLength = GetWindowTextLength() + 1;
  319. GetWindowText( strValue.GetBuffer( nValueLength ), nValueLength );
  320. strValue.ReleaseBuffer();
  321. }
  322. CListNotify listNotify;
  323. listNotify.m_hdrNotify.hwndFrom = m_hWnd;
  324. listNotify.m_hdrNotify.idFrom = GetDlgCtrlID();
  325. listNotify.m_hdrNotify.code = LCN_ENDEDIT;
  326. listNotify.m_nItem = m_nItem;
  327. listNotify.m_nSubItem = m_nSubItem;
  328. listNotify.m_nExitChar = m_nExitChar;
  329. listNotify.m_lpszItemText = strValue;
  330. listNotify.m_lpItemDate = NULL;
  331. // forward notification to parent
  332. FORWARD_WM_NOTIFY( wndParent, listNotify.m_hdrNotify.idFrom, &listNotify.m_hdrNotify, ::SendMessage );
  333. }
  334. ShowWindow( SW_HIDE );
  335. }
  336. UINT OnGetDlgCode( LPMSG lpMessage )
  337. {
  338. return DLGC_WANTALLKEYS;
  339. }
  340. void OnChar( TCHAR nChar, UINT nRepCnt, UINT nFlags )
  341. {
  342. switch ( nChar )
  343. {
  344. case VK_TAB:
  345. case VK_RETURN:
  346. case VK_ESCAPE: {
  347. m_nExitChar = nChar;
  348. CWindow wndParent( GetParent() );
  349. if ( wndParent.IsWindow() )
  350. wndParent.SetFocus();
  351. }
  352. break;
  353. default: SetMsgHandled( !IsValid( nChar ) );
  354. break;
  355. }
  356. }
  357. };