QComboBox.cpp
上传用户:cszhwei
上传日期:2007-01-01
资源大小:37k
文件大小:31k
源码类别:

组合框控件

开发平台:

Visual C++

  1. /************************************
  2.   REVISION LOG ENTRY
  3.   Revision By: Mihai Filimon
  4.   Revised on 9/16/98 2:20:27 PM
  5.   Comments: QComboBox.cpp : implementation file
  6.  ************************************/
  7. #include "stdafx.h"
  8. #include "QComboBox.h"
  9. #include <math.h>
  10. #include <afxpriv.h>
  11. #ifdef _DEBUG
  12. #define new DEBUG_NEW
  13. #undef THIS_FILE
  14. static char THIS_FILE[] = __FILE__;
  15. #endif
  16. /////////////////////////////////////////////////////////////////////////////
  17. // CQComboBox
  18. #define NotifyWindow(pWnd,message,wParam,lParam) if (pWnd) pWnd->SendMessage(message, (WPARAM)wParam, (LPARAM)lParam)
  19. CBrush CQComboBox::m_brBkGnd(defaultRGBBkGnd);
  20. CFont CQComboBox::m_font;
  21. CMap<CQComboBox*,CQComboBox*, BOOL, BOOL> CQComboBox::m_mapUnloadedQCombos;
  22. static const LOGFONT logFontPages =
  23. {
  24. /*LONG lfHeight*/8,
  25. /*LONG lfWidth*/0,
  26. /*LONG lfEscapement*/0,
  27. /*LONG lfOrientation*/0,
  28. /*LONG lfWeight*/FW_NORMAL,
  29. /*BYTE lfItalic*/FALSE,
  30. /*BYTE lfUnderline*/FALSE,
  31. /*BYTE lfStrikeOut*/FALSE,
  32. /*BYTE lfCharSet*/ANSI_CHARSET,
  33. /*BYTE lfOutPrecision*/0,
  34. /*BYTE lfClipPrecision*/0,
  35. /*BYTE lfQuality*/DEFAULT_QUALITY,
  36. /*BYTE lfPitchAndFamily*/DEFAULT_PITCH,
  37. /*CHAR lfFaceName[LF_FACESIZE]*/_T("MS Sans Serif")
  38. };
  39. // Function name : CQComboBox::CQComboBox
  40. // Description     : default constuctor
  41. // Return type : 
  42. CQComboBox::CQComboBox(TLine fctLine, TLinePartial fctLinePartial, LPARAM lParam)
  43. {
  44. m_lParam = lParam;
  45. m_QuickLoader.SetParent(this);
  46. RegClassQComboBox();
  47. m_pListBox = NULL;
  48. m_pEdit = NULL;
  49. m_bCaptured = FALSE;
  50. m_fctLine = fctLine;
  51. m_fctLinePartial = fctLinePartial;
  52. m_nCountVisible = 0;
  53. SetRateWidth(0.0);
  54. SetMultipleHeight();
  55. m_fctLoadFunction = LoadPartialListBox;
  56. m_mapUnloadedQCombos[this] = !IsAlreadyLoad();
  57. //When you callthe contructor, you need to attach two function.
  58. //The first, for giving line number nIndex
  59. //The second, for fiving numer of line which start with a given string.
  60. // If you don't write that functions, especialy m_fctLine, you will have some suprises
  61. ASSERT(m_fctLine);
  62. }
  63. // Function name : CQComboBox::~CQComboBox
  64. // Description     : virtual destructor
  65. // Return type : 
  66. CQComboBox::~CQComboBox()
  67. {
  68. m_mapUnloadedQCombos.RemoveKey(this);
  69. }
  70. BEGIN_MESSAGE_MAP(CQComboBox, CWnd)
  71. //{{AFX_MSG_MAP(CQComboBox)
  72. ON_WM_DESTROY()
  73. ON_WM_LBUTTONDOWN()
  74. ON_WM_WINDOWPOSCHANGED()
  75. ON_WM_PAINT()
  76. ON_WM_LBUTTONUP()
  77. ON_WM_MOUSEMOVE()
  78. ON_WM_SETFOCUS()
  79. ON_WM_CREATE()
  80. ON_WM_TIMER()
  81. //}}AFX_MSG_MAP
  82. END_MESSAGE_MAP()
  83. /////////////////////////////////////////////////////////////////////////////
  84. // CQComboBox message handlers
  85. UINT CQComboBox::m_nSelChange = NULL;
  86. UINT CQComboBox::m_nLoading = NULL;
  87. UINT CQComboBox::m_nLoaded = NULL;
  88. // Function name : CQComboBox::RegClassQComboBox
  89. // Description     : Register this window class
  90. // Return type : BOOL 
  91. BOOL CQComboBox::RegClassQComboBox()
  92. {
  93. WNDCLASS wndClass;
  94. wndClass.style = CS_DBLCLKS;
  95. wndClass.lpfnWndProc = ::DefWindowProc;
  96. wndClass.cbClsExtra = NULL;
  97. wndClass.cbWndExtra = NULL;
  98. wndClass.hInstance = AfxGetInstanceHandle();
  99. wndClass.hIcon = NULL;
  100. wndClass.hCursor = AfxGetApp()->LoadStandardCursor(IDC_ARROW);
  101. wndClass.hbrBackground = (HBRUSH)m_brBkGnd;
  102. wndClass.lpszMenuName = NULL;
  103. wndClass.lpszClassName = wndClassName;
  104. BOOL bResult = AfxRegisterClass(&wndClass);
  105. if (bResult)
  106. {
  107. if (!m_nSelChange)
  108. m_nSelChange = RegisterWindowMessage(defaultSelChange);
  109. if (!m_nLoading)
  110. m_nLoading = RegisterWindowMessage(defaultLoading);
  111. if (!m_nLoaded)
  112. m_nLoaded = RegisterWindowMessage(defaultLoaded);
  113. if (!m_font.GetSafeHandle())
  114. {
  115. //At the first call set the new font
  116. m_font.CreateFontIndirect(&logFontPages);
  117. }
  118. }
  119. return bResult;
  120. }
  121. CQComboBox* CQComboBox::m_pActiveMCBox = NULL;
  122. CQComboBox::CWindowProcs CQComboBox::m_wndProcs;
  123. // Function name : CQComboBox::ListBoxWindowProc
  124. // Description     : ListControl window procedure
  125. // Return type : LRESULT CALLBACK 
  126. // Argument         : HWND hWnd
  127. // Argument         : UINT nMsg
  128. // Argument         : WPARAM wParam
  129. // Argument         : LPARAM lParam
  130. LRESULT CALLBACK CQComboBox::ListBoxWindowProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
  131. {
  132. if (CQComboBox* pOwner = CQComboBox::m_pActiveMCBox)
  133. if (!pOwner->ForwardMessage(nMsg, wParam, lParam))
  134. return NULL;
  135. return CallWindowProc( CQComboBox::m_wndProcs.GetOldListBoxProcedure(hWnd), hWnd, nMsg, wParam, lParam );
  136. }
  137. // Function name : CQComboBox::ParentWindowProc
  138. // Description     : Parent window procedure.
  139. // Return type : LRESULT CALLBACK 
  140. // Argument         : HWND hWnd
  141. // Argument         : UINT nMsg
  142. // Argument         : WPARAM wParam
  143. // Argument         : LPARAM lParam
  144. LRESULT CALLBACK CQComboBox::ParentWindowProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
  145. {
  146. CQComboBox* pOwner = CQComboBox::m_pActiveMCBox;
  147. CQComboBox* pFirst = GetFirstQComboBox();
  148. {
  149. switch (nMsg)
  150. {
  151. case WM_KICKIDLE:
  152. {
  153. //Start to load items, after 3 seconds.
  154. if (pFirst)
  155. pFirst->SetTimer(QIDTIMERSTARTLOADITEMS, QTIMESTARTLOADITEMS, NULL);
  156. break;
  157. }
  158. case WM_COMMAND:
  159. case WM_SYSCOMMAND:
  160. case WM_LBUTTONDOWN:
  161. case WM_NCLBUTTONDOWN:
  162. {
  163. if (pFirst)
  164. {
  165. pFirst->KillTimer(QIDTIMERSTARTLOADITEMS);
  166. pFirst->KillTimer(QIDTIMERLOADITEMS);
  167. };
  168. if (pOwner)
  169. {
  170. BOOL bDropped = pOwner->IsDropedDown();
  171. pOwner->DropDown(FALSE);
  172. if (nMsg == WM_COMMAND)
  173. if (LOWORD(wParam) == IDOK)
  174. {
  175. pOwner->SelectCurrentItem();
  176. return FALSE;
  177. }
  178. else
  179. if (LOWORD(wParam) == IDCANCEL)
  180. if (bDropped)
  181. return FALSE;
  182. break;
  183. }
  184. }
  185. }
  186. };
  187. WNDPROC wndProc = CQComboBox::m_wndProcs.GetOldParentProcedure(hWnd);
  188. ASSERT (wndProc);
  189. return CallWindowProc( wndProc, hWnd, nMsg, wParam, lParam );
  190. }
  191. // Function name : CQComboBox::EditWindowProc
  192. // Description     : Edit window procedure
  193. // Return type : LRESULT CALLBACK 
  194. // Argument         : HWND hWnd
  195. // Argument         : UINT nMsg
  196. // Argument         : WPARAM wParam
  197. // Argument         : LPARAM lParam
  198. LRESULT CALLBACK CQComboBox::EditWindowProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
  199. {
  200. CQComboBox* pOwner = CQComboBox::m_pActiveMCBox;
  201. switch (nMsg)
  202. {
  203. case WM_SETFOCUS:
  204. {
  205. CQComboBox::m_pActiveMCBox = (CQComboBox*)CWnd::FromHandle(::GetParent(hWnd));
  206. break;
  207. }
  208. case WM_KILLFOCUS:
  209. {
  210. if (pOwner)
  211. {
  212. pOwner->DropDown(FALSE);
  213. CQComboBox::m_pActiveMCBox = NULL;
  214. }
  215. break;
  216. }
  217. case WM_KEYDOWN:
  218. case WM_SYSKEYDOWN:
  219. {
  220. int nStep = 0;
  221. if (pOwner)
  222. switch ((int) wParam)
  223. {
  224. case VK_NEXT:
  225. {
  226. if (nStep == 0)
  227. nStep = +pOwner->GetVisibleCount();
  228. }
  229. case VK_PRIOR:
  230. {
  231. if (nStep == 0)
  232. nStep = -pOwner->GetVisibleCount();
  233. }
  234. case VK_UP:
  235. {
  236. if (nStep == 0)
  237. nStep = -1;
  238. }
  239. case VK_DOWN:
  240. {
  241. if (nStep == 0)
  242. nStep = +1;
  243. if (abs(nStep) > 1 || ((abs(nStep) == 1) && GetAsyncKeyState(VK_MENU) >= 0))
  244. {
  245. pOwner->LoadPartial(pOwner->m_QuickLoader.GetItemLine(pOwner->GetCurrentItem()) + nStep, nStep/abs(nStep) * pOwner->GetVisibleCount());
  246. pOwner->SetCurrentItem(pOwner->GetCurrentItem() + nStep);
  247. pOwner->SelectCurrentItem();
  248. break;
  249. }
  250. }
  251. case defaultDropDownKey:
  252. {
  253. pOwner->DropDown(!pOwner->IsDropedDown());
  254. break;
  255. }
  256. }
  257. break;
  258. }
  259. }
  260. return CallWindowProc( CQComboBox::m_wndProcs.GetOldEditProcedure(hWnd), hWnd, nMsg, wParam, lParam );
  261. }
  262. // Function name : CQComboBox::OnInit
  263. // Description     : Init the control
  264. // Return type : BOOL 
  265. BOOL CQComboBox::OnInit()
  266. {
  267. // You must already attach a function who give me a line.
  268. ASSERT (m_fctLine != NULL);
  269. ASSERT (m_font.GetSafeHandle());
  270. SetFont(&m_font);
  271. ModifyStyle(WS_OVERLAPPED , WS_TABSTOP);
  272. m_pEdit = new CEdit();
  273. m_pListBox = new CListBox();
  274. if (m_pEdit->Create(WS_CHILD | WS_VISIBLE | defaultEditStyle, CRect(0,0,0,0), this, IDEDIT ))
  275. {
  276. ModifyStyleEx(0, WS_EX_STATICEDGE);
  277. m_pEdit->SetFont(&m_font);
  278. if (m_pListBox->Create(WS_BORDER | WS_CHILD | defaultListBoxStyle , CRect(0,0,0,0), GetDesktopWindow(), IDListBox))
  279. {
  280. m_pListBox->SetFont(&m_font);
  281. //Set the refernce to this object in user data dword
  282. ::SetWindowLong(m_pListBox->m_hWnd, GWL_USERDATA, (long)this);
  283. ::SetWindowLong(m_pListBox->m_hWnd, GWL_STYLE, GetWindowLong(m_pListBox->m_hWnd, GWL_STYLE) | WS_CLIPSIBLINGS | WS_OVERLAPPED);
  284. m_pListBox->ModifyStyleEx(0, WS_EX_TOOLWINDOW);
  285. m_pListBox->SetWindowPos(&CWnd::wndTopMost,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE);
  286. ListView_SetExtendedListViewStyle(m_pListBox->m_hWnd, LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT);
  287. Resize();
  288. m_wndProcs.AddEdit(GetEdit(), EditWindowProc);
  289. m_wndProcs.AddListBox(GetListBox(), ListBoxWindowProc);
  290. m_wndProcs.AddParent(GetParent(), ParentWindowProc);
  291. m_nCountVisible = GetVisibleCount();
  292. return TRUE;
  293. }
  294. }
  295. return FALSE;
  296. }
  297. // Function name : CQComboBox::PreSubclassWindow
  298. // Description     : Call to subclass window
  299. // Return type : void 
  300. void CQComboBox::PreSubclassWindow() 
  301. {
  302. CWnd::PreSubclassWindow();
  303. OnInit();
  304. }
  305. // Function name : CQComboBox::OnDestroy
  306. // Description     : Remove all dependent datas.
  307. // Return type : void 
  308. void CQComboBox::OnDestroy() 
  309. {
  310. CWnd::OnDestroy();
  311. m_wndProcs.RemoveEdit(GetEdit());
  312. m_wndProcs.RemoveListBox(GetListBox());
  313. m_wndProcs.RemoveParent(GetParent());
  314. if (CListBox* pList = GetListBox())
  315. delete pList;
  316. if (CEdit* pEdit = GetEdit())
  317. delete pEdit;
  318. m_pListBox = NULL;
  319. m_pEdit = NULL;
  320. }
  321. // Function name : CQComboBox::GetListBox
  322. // Description     : return the list control for 
  323. // Return type : CListBox* 
  324. CListBox* CQComboBox::GetListBox()
  325. {
  326. return m_pListBox;
  327. }
  328. // Function name : CQComboBox::GetEdit
  329. // Description     : retirn  pointer to edit control inside of thsi control
  330. // Return type : CEdit* 
  331. CEdit* CQComboBox::GetEdit()
  332. {
  333. return m_pEdit;
  334. }
  335. // Function name : CQComboBox::DrawButton
  336. // Description     : Draw down button
  337. // Return type : void 
  338. // Argument         : CDC * pDC
  339. // Argument         : CRect r
  340. // Argument         : BOOL bDown
  341. void CQComboBox::DrawButton(CDC * pDC, CRect r, BOOL bDown)
  342. {
  343. CPen penWhite(PS_SOLID,1,RGB(255,255,255));
  344. CPen penBlack(PS_SOLID,1,RGB(0,0,0));
  345. pDC->FrameRect(r,&CBrush(RGB(128,128,128)));
  346. if (!bDown)
  347. {
  348. pDC->SelectObject(&penWhite);
  349.  pDC->MoveTo(r.left, r.bottom - 2);
  350.  pDC->LineTo(r.left, r.top);
  351.  pDC->LineTo(r.right - 1, r.top);
  352. }
  353. CBitmap bitmapOEM;
  354. if (bitmapOEM.LoadOEMBitmap(OBM_COMBO))
  355. {
  356. CDC dcMem;
  357. if (dcMem.CreateCompatibleDC(pDC))
  358. {
  359. BITMAP b; bitmapOEM.GetBitmap(&b);
  360. int leftC = max((r.Width() - b.bmWidth) / 2,1);
  361. int topC = max((r.Height() - b.bmHeight) / 2,1);
  362. if (bDown)
  363. {
  364. leftC++;
  365. topC++;
  366. }
  367. CBitmap* pOldBitmap = dcMem.SelectObject(&bitmapOEM);
  368. pDC->BitBlt(r.left + leftC, r.top + topC, r.Width() - (leftC + 1), r.Height() - (topC), &dcMem, 0,0, SRCCOPY);
  369. pOldBitmap = dcMem.SelectObject(pOldBitmap);
  370. }
  371. }
  372. }
  373. // Function name : CQComboBox::OnPaint
  374. // Description     : On Draw function
  375. // Return type : void 
  376. void CQComboBox::OnPaint() 
  377. {
  378. CPaintDC dc(this); // device context for painting
  379. CRect r; GetClientRect(r);
  380. r.right--;
  381. dc.MoveTo(r.left, r.bottom);
  382.  dc.LineTo(r.left, r.top);
  383.  dc.LineTo(r.right, r.top);
  384.  dc.LineTo(r.right, r.bottom);
  385. r.left = r.right - defaultSizeDX;
  386. r.InflateRect(0,-2);r.bottom++;r.right--;r.left++;
  387. m_rectBtn = r;
  388. DrawButton(&dc, m_rectBtn);
  389. }
  390. // Function name : CQComboBox::Resize
  391. // Description     : Call to remove the edit and list controls
  392. // Return type : void 
  393. void CQComboBox::Resize()
  394. {
  395. ASSERT (GetListBox());
  396. CRect r;
  397. GetWindowRect(r);
  398. SetWindowPos(0, 0, 0, r.Width(), defaultSizeDY, SWP_NOMOVE | SWP_NOZORDER | SWP_NOMOVE);
  399. // Set the height and width of edit control
  400. GetClientRect(r);
  401. r.InflateRect(-1,-2); r.bottom++;
  402. r.right -= defaultSizeDX;
  403. GetEdit()->MoveWindow(r.left, r.top, r.Width(), r.Height());
  404. // Set the height and width of list control
  405. GetWindowRect(r);
  406. int dy = r.Height();
  407. r.top = r.bottom;
  408. r.left++;r.right--;
  409. r.bottom += m_nMultipleHeight * dy;
  410. r.right += int(m_dWidthList * r.Width());
  411. GetListBox()->MoveWindow(r.left, r.top, r.Width(), r.Height());
  412. }
  413. // Function name : CQComboBox::DropDown
  414. // Description     : DropDown
  415. // Return type : void 
  416. // Argument         : BOOL bDown
  417. void CQComboBox::DropDown(BOOL bDown)
  418. {
  419. if (IsWindowVisible())
  420. if (IsDropedDown() != bDown)
  421. {
  422. Resize();
  423. LoadPartial(0, +GetVisibleCount());
  424. GetListBox()->ShowWindow(bDown ? SW_SHOW : SW_HIDE);
  425. if (bDown)
  426. GetEdit()->SetFocus();
  427. }
  428. }
  429. // Function name : CQComboBox::IsDropedDown
  430. // Description     : If the list control is dropped downd, return TRUE
  431. // Return type : BOOL 
  432. BOOL CQComboBox::IsDropedDown()
  433. {
  434. return GetListBox()->IsWindowVisible();
  435. }
  436. // Function name : CQComboBox::OnWindowPosChanged
  437. // Description     : 
  438. // Return type : void 
  439. // Argument         : WINDOWPOS FAR* lpwndpos
  440. void CQComboBox::OnWindowPosChanged(WINDOWPOS FAR* lpwndpos) 
  441. {
  442. CWnd::OnWindowPosChanged(lpwndpos);
  443. Resize();
  444. }
  445. // Function name : CQComboBox::OnLButtonDown
  446. // Description     : 
  447. // Return type : void 
  448. // Argument         : UINT nFlags
  449. // Argument         : CPoint point
  450. void CQComboBox::OnLButtonDown(UINT nFlags, CPoint point) 
  451. {
  452. if (m_rectBtn.PtInRect(point))
  453. {
  454. SetButton();
  455. DropDown(!IsDropedDown());
  456. }
  457. CWnd::OnLButtonDown(nFlags, point);
  458. }
  459. // Function name : CQComboBox::OnLButtonUp
  460. // Description     : 
  461. // Return type : void 
  462. // Argument         : UINT nFlags
  463. // Argument         : CPoint point
  464. void CQComboBox::OnLButtonUp(UINT nFlags, CPoint point) 
  465. {
  466. ReleaseButton();
  467. CWnd::OnLButtonUp(nFlags, point);
  468. }
  469. // Function name : CQComboBox::OnMouseMove
  470. // Description     : 
  471. // Return type : void 
  472. // Argument         : UINT nFlags
  473. // Argument         : CPoint point
  474. void CQComboBox::OnMouseMove(UINT nFlags, CPoint point) 
  475. {
  476. if (m_bCaptured)
  477. {
  478. CPoint p; ::GetCursorPos(&p);
  479. ScreenToClient(&p);
  480. if (!m_rectBtn.PtInRect(p))
  481. ReleaseButton();
  482. }
  483. CWnd::OnMouseMove(nFlags, point);
  484. }
  485. // Function name : CQComboBox::ReleaseButton
  486. // Description     : Call to release the capture and image of button. After SetButton()
  487. // Return type : void 
  488. void CQComboBox::ReleaseButton()
  489. {
  490. if (m_bCaptured)
  491. {
  492. ReleaseCapture();
  493. CDC* pDC = GetDC();
  494. DrawButton(pDC, m_rectBtn);
  495. ReleaseDC(pDC);
  496. m_bCaptured = FALSE;
  497. }
  498. }
  499. // Function name : CQComboBox::SetButton
  500. // Description     : 
  501. // Return type : void 
  502. void CQComboBox::SetButton()
  503. {
  504. if (!m_bCaptured)
  505. {
  506. SetCapture();
  507. CDC* pDC = GetDC();
  508. DrawButton(pDC, m_rectBtn, TRUE);
  509. ReleaseDC(pDC);
  510. m_bCaptured = TRUE;
  511. }
  512. }
  513. // Function name : CQComboBox::ForwardMessage
  514. // Description     : This function is called by ListBoxWindowProc
  515. // Return type : void 
  516. // Argument         : UINT nMsg
  517. // Argument         : WPARAM wParam
  518. // Argument         : LPARAM lParam
  519. BOOL CQComboBox::ForwardMessage(UINT nMsg, WPARAM wParam, LPARAM lParam)
  520. {
  521. ASSERT (GetListBox());
  522. switch (nMsg)
  523. {
  524. case WM_MOUSEMOVE:
  525. case WM_LBUTTONDOWN:
  526. {
  527. BOOL bOutside = TRUE;
  528. int nIndex = GetListBox()->ItemFromPoint(CPoint(LOWORD(wParam), HIWORD(lParam)), bOutside);
  529. if (GetCurrentItem() != nIndex)
  530. SetCurrentItem(nIndex);
  531. if (nMsg == WM_LBUTTONDOWN)
  532. {
  533. DropDown(FALSE);
  534. SelectCurrentItem();
  535. }
  536. break;
  537. }
  538. case WM_VSCROLL:
  539. {
  540. CListBox* pListBox = GetListBox();
  541. UINT nScrollCode =  (int) LOWORD(wParam);
  542. int nHM = NULL, nStep = NULL;
  543. switch ( nScrollCode )
  544. {
  545. case SB_LINEDOWN:
  546. case SB_PAGEDOWN:
  547. {
  548. nHM = GetVisibleCount();
  549. nStep = (nScrollCode == SB_LINEDOWN ? 1 : nHM);
  550. }
  551. case SB_PAGEUP:
  552. case SB_LINEUP:
  553. {
  554. if (!nHM)
  555. {
  556. nHM = -GetVisibleCount();
  557. nStep = (nScrollCode == SB_LINEUP ? -1 : nHM);
  558. }
  559. int nPos = pListBox->GetTopIndex();
  560. LoadPartial( nPos, nHM);
  561. pListBox->SetTopIndex(nPos + nStep);
  562. pListBox->SetScrollPos(SB_VERT,  pListBox->GetTopIndex());
  563. break;
  564. }
  565. case SB_THUMBPOSITION:
  566. {
  567. int nPos = LoadPartial(HIWORD(wParam), GetVisibleCount());
  568. pListBox->SetScrollPos(SB_VERT,  HIWORD(wParam));
  569. pListBox->SetTopIndex(nPos);
  570. break;
  571. }
  572. }
  573. return FALSE;
  574. break;
  575. }
  576. }
  577. return TRUE;
  578. }
  579. // Function name : CQComboBox::OnSetFocus
  580. // Description     : When control have focus then edit will take the focus
  581. // Return type : void 
  582. // Argument         : CWnd* pOldWnd
  583. void CQComboBox::OnSetFocus(CWnd* pOldWnd) 
  584. {
  585. CWnd::OnSetFocus(pOldWnd);
  586. GetEdit()->SetFocus();
  587. }
  588. // Function name : CQComboBox::OnCommand
  589. // Description     : When something is happen in edit control, notify the list control
  590. // Return type : BOOL 
  591. // Argument         : WPARAM wParam
  592. // Argument         : LPARAM lParam
  593. BOOL CQComboBox::OnCommand(WPARAM wParam, LPARAM lParam) 
  594. {
  595. if (LOWORD(wParam) == IDEDIT)
  596. if (HIWORD(wParam) == EN_CHANGE)
  597. {
  598. ASSERT( GetEdit() && GetEdit()->GetDlgCtrlID() == IDEDIT);
  599. CString text,t ;
  600. GetEdit()->GetWindowText(t);
  601. Search(t);
  602. }
  603. return CWnd::OnCommand(wParam, lParam);
  604. }
  605. // Function name : CQComboBox::Search
  606. // Description     : Look for the lpszFindItem
  607. // Return type : void 
  608. // Argument         : LPCTSTR lpszFindItem
  609. void CQComboBox::Search(LPCTSTR lpszFindItem)
  610. {
  611. if (CListBox* pListBox = GetListBox())
  612. {
  613. LoadPartial(0, GetVisibleCount());
  614. int nItem = pListBox->FindString(-1, lpszFindItem);
  615. if (nItem < 0)
  616. {
  617. int tLine = LinePartial(lpszFindItem);
  618. LoadPartial(tLine - GetVisibleCount(), 2 * GetVisibleCount());
  619. nItem = pListBox->FindString(-1, lpszFindItem);
  620. }
  621. SetCurrentItem(nItem);
  622. }
  623. }
  624. // Function name : CQComboBox::SelectCurrentItem
  625. // Description     : Select the current item of list. Called if user click the mouse, oor press ENTER
  626. // Return type : void 
  627. void CQComboBox::SelectCurrentItem()
  628. {
  629. int nIndex = GetCurrentItem();
  630. if (nIndex != LB_ERR)
  631. {
  632. CString sItem; GetListBox()->GetText(nIndex, sItem);
  633. GetListBox()->SetScrollPos(SB_VERT, GetListBox()->GetTopIndex());
  634. GetEdit()->SetWindowText(sItem);
  635. //Notify the parent that one item was changed
  636. if (nIndex >= 0)
  637. if (CWnd* pParent = GetParent())
  638. pParent->SendMessage(m_nSelChange, (WPARAM)GetDlgCtrlID(), (LPARAM)m_hWnd);
  639. }
  640. }
  641. // Function name : CQComboBox::GetCurrentItem
  642. // Description     : Get current item from list control
  643. // Return type : int 
  644. int CQComboBox::GetCurrentItem()
  645. {
  646. return GetListBox()->GetCurSel();
  647. }
  648. // Function name : CQComboBox::SetCurrentItem
  649. // Description     : Set current item from list control to nIndex
  650. // Return type : void 
  651. // Argument         : int nIndex
  652. void CQComboBox::SetCurrentItem(int nIndex)
  653. {
  654. GetListBox()->SetCurSel(nIndex);
  655. }
  656. // Function name : CQComboBox::OnCreate
  657. // Description     : Call OnInit if control is created dynamically
  658. // Return type : int 
  659. // Argument         : LPCREATESTRUCT lpCreateStruct
  660. int CQComboBox::OnCreate(LPCREATESTRUCT lpCreateStruct) 
  661. {
  662. if (CWnd::OnCreate(lpCreateStruct) == -1)
  663. return -1;
  664. OnInit();
  665. return 0;
  666. }
  667. // Function name : CQComboBox::SetRateWidth
  668. // Description     : This function will changes the width of inside listcontrol
  669. // Return type : double 
  670. // Argument         : double dWidthList
  671. double CQComboBox::SetRateWidth(double dWidthList)
  672. {
  673. double dResult = m_dWidthList;
  674. m_dWidthList = fabs(dWidthList);
  675. return dResult;
  676. }
  677. // Function name : CQComboBox::SetMultipleHeight
  678. // Description     : 
  679. // Return type : int 
  680. // Argument         : int nMHeight
  681. int CQComboBox::SetMultipleHeight(int nMHeight)
  682. {
  683. int nResult = m_nMultipleHeight;
  684. m_nMultipleHeight = abs(nMHeight);
  685. if (::IsWindow(m_hWnd))
  686. {
  687. Resize();
  688. m_nCountVisible = GetVisibleCount();
  689. }
  690. return nResult;
  691. }
  692. // Function name : CQComboBox::GetCountItem
  693. // Description     : 
  694. // Return type : int 
  695. int CQComboBox::GetCountItem()
  696. {
  697. return m_nCountItems;
  698. }
  699. // Function name : CQComboBox::SetCountItems
  700. // Description     : Set the count of items list box.
  701. // Return type : void 
  702. // Argument         : int nCount
  703. void CQComboBox::SetCountItems(int nCount)
  704. {
  705. // Already, you must call GetVisibleCount()
  706. ASSERT (m_nCountVisible != 0);
  707. m_nCountItems = nCount;
  708. // If this need vertical scroll bar, I will put WS_VSCROLL style
  709. if ( m_nCountItems >= m_nCountVisible)
  710. {
  711. CWnd* pWnd = GetListBox();
  712. // Already you must call OnInit, in fact, you must call SubclassDlgItem , or Create function
  713. ASSERT (pWnd != NULL);
  714. pWnd->ModifyStyle(0, WS_VSCROLL);
  715. SCROLLINFO sInfo;
  716.  sInfo.cbSize = sizeof(sInfo);
  717.  sInfo.fMask = SIF_ALL;
  718.  sInfo.nMin = 0;
  719.  sInfo.nMax = m_nCountItems - 1;
  720.  sInfo.nPage = m_nCountVisible - 1;
  721.  sInfo.nPos = 0;
  722.  sInfo.nTrackPos = 0;
  723. pWnd->SetScrollInfo(SB_VERT, &sInfo);
  724. }
  725. }
  726. // Function name : CQComboBox::GetVisibleCount
  727. // Description     : Get count of visible items.
  728. // Return type : int 
  729. int CQComboBox::GetVisibleCount()
  730. {
  731. CListBox* pListBox = GetListBox();
  732. ASSERT( pListBox );
  733. CRect r;
  734. if (pListBox->GetItemRect(0, r) == LB_ERR)
  735. {
  736. int nItem = pListBox->AddString(_T(""));
  737. pListBox->GetItemRect(0, r);
  738. pListBox->DeleteString(nItem);
  739. }
  740. CRect rClient; pListBox->GetClientRect(rClient);
  741. return rClient.Height() / r.Height() + 1;
  742. }
  743. // Function name : CQComboBox::AlreadyLoadPartialListBox
  744. // Description     : 
  745. // Return type : void 
  746. // Argument         : int nLineFrom
  747. // Argument         : int nHowMany
  748. int CQComboBox::AlreadyLoadPartialListBox(int nLineFrom, int nHowMany)
  749. {
  750. //Already the load was made
  751. return nLineFrom;
  752. }
  753. // Function name : CQComboBox::GetFirstQComboBox
  754. // Description     : Statical function. Return first element as QComboBox
  755. // Return type : CQComboBox* 
  756. CQComboBox* CQComboBox::GetFirstQComboBox()
  757. {
  758. if (POSITION position = m_mapUnloadedQCombos.GetStartPosition())
  759. {
  760. CQComboBox* pCombo = NULL;
  761. BOOL bLoaded = TRUE;
  762. m_mapUnloadedQCombos.GetNextAssoc(position, pCombo, bLoaded);
  763. return pCombo;
  764. }
  765. return NULL;
  766. }
  767. // Function name : CQComboBox::OnTimer
  768. // Description     : 
  769. // Return type : void 
  770. // Argument         : UINT nIDEvent
  771. void CQComboBox::OnTimer(UINT nIDEvent) 
  772. {
  773. switch (nIDEvent)
  774. {
  775. case QIDTIMERSTARTLOADITEMS:
  776. {
  777. KillTimer(QIDTIMERSTARTLOADITEMS);
  778. SetTimer(QIDTIMERLOADITEMS, QTIMELOADITEMS, NULL);
  779. }
  780. case QIDTIMERLOADITEMS:
  781. {
  782. POSITION position = m_mapUnloadedQCombos.GetStartPosition();
  783. while (position)
  784. {
  785. CQComboBox* pCombo = NULL;
  786. BOOL bLoaded = TRUE;
  787. m_mapUnloadedQCombos.GetNextAssoc(position, pCombo, bLoaded);
  788. if (pCombo->IsAlreadyLoad())
  789. m_mapUnloadedQCombos.RemoveKey(pCombo);
  790. else
  791. {
  792. pCombo->LoadPartial(0, GetVisibleCount());
  793. }
  794. }
  795. break;
  796. }
  797. }
  798. CWnd::OnTimer(nIDEvent);
  799. }
  800. // Function name : CQComboBox::IsAlreadyLoad
  801. // Description     : Return TRUE if listvox is already loaded.
  802. // Return type : BOOL 
  803. BOOL CQComboBox::IsAlreadyLoad()
  804. {
  805. return m_fctLoadFunction == AlreadyLoadPartialListBox;
  806. }
  807. // Function name : CQComboBox::LoadPartial
  808. // Description     : 
  809. // Return type : void 
  810. // Argument         : int nLineFrom
  811. // Argument         : int nHowMany
  812. int CQComboBox::LoadPartial(int nLineFrom, int nHowMany)
  813. {
  814. return (this->*m_fctLoadFunction)(nLineFrom, nHowMany);
  815. }
  816. // Function name : CQComboBox::LoadPartialListBox
  817. // Description     : 
  818. // Return type : void 
  819. int CQComboBox::LoadPartialListBox(int nLineFrom, int nHowMany)
  820. {
  821. return m_QuickLoader.Load(nLineFrom, nHowMany);
  822. }
  823. // Function name : CQComboBox::Line
  824. // Description     : Return line nLine, by calling own statical function
  825. // Return type : LPCTSTR 
  826. // Argument         : int nLine
  827. // Argument         : LPARAM & lParam
  828. LPCTSTR CQComboBox::Line(int nLine, LPARAM& lParamItem)
  829. {
  830. return m_fctLine(nLine, lParamItem, m_lParam);
  831. }
  832. // Function name : CQComboBox::LinePartial
  833. // Description     : return the index of real line, which has string equal with lpszItemPartial
  834. // Return type : int 
  835. // Argument         : LPCTSTR lpszItemPartial
  836. int CQComboBox::LinePartial(LPCTSTR lpszItemPartial)
  837. {
  838. if (m_fctLinePartial)
  839. return m_fctLinePartial(lpszItemPartial, m_lParam);
  840. return 0;
  841. }
  842. //QSnapLoader implementation
  843. int CQComboBox::QSnapLoader::SNodeItemsInfo::m_nCountRef = 0;
  844. // Function name : CQComboBox::QSnapLoader::~QSnapLoader
  845. // Description     : virtual destructor
  846. // Return type : 
  847. CQComboBox::QSnapLoader::~QSnapLoader()
  848. {
  849. SNodeItemsInfo* pNodeNext = m_pFirstNode;
  850. while (pNodeNext)
  851. {
  852. SNodeItemsInfo* pNodeDelete = pNodeNext;
  853. pNodeNext = pNodeNext->m_pNextNode;
  854. delete pNodeDelete;
  855. };
  856. }
  857. // Function name : CQComboBox::QSnapLoader::QSnapLoader
  858. // Description     : default constructor
  859. // Return type : 
  860. CQComboBox::QSnapLoader::QSnapLoader()
  861. {
  862. m_pFirstNode = new SNodeItemsInfo(0,0,0);
  863. }
  864. // Function name : CQComboBox::QSnapLoader::SetParent
  865. // Description     : Set the parent of this structure
  866. // Return type : void 
  867. // Argument         : CQComboBox * pParent
  868. void CQComboBox::QSnapLoader::SetParent(CQComboBox * pParent)
  869. {
  870. m_pParent = pParent;
  871. }
  872. // Function name : CQComboBox::QSnapLoader::GetListNodes
  873. // Description     : 
  874. // Return type : CString 
  875. CString CQComboBox::QSnapLoader::GetListNodes()
  876. {
  877. CString text;
  878. SNodeItemsInfo* pIncreaseNode = m_pFirstNode;
  879. int s = 0;
  880. while (pIncreaseNode)
  881. {
  882. CString t;
  883. t.Format(_T("(%i,%i,%i, [%i,%i])rn"), pIncreaseNode->m_nItemLine, pIncreaseNode->m_nCount, pIncreaseNode->m_nItemLB, pIncreaseNode->GetLastLine(), pIncreaseNode->GetLastItem());
  884. text += t;
  885. s += pIncreaseNode->m_nCount;
  886. pIncreaseNode = pIncreaseNode->m_pNextNode;
  887. }
  888. CString t;
  889. t.Format(_T("Count loaded: %i, Count items. listbox() %i"), s, m_pParent->GetListBox()->GetCount());
  890. text += t;
  891. return text;
  892. }
  893. // Function name : CQComboBox::QSnapLoader::Load
  894. // Description     : 
  895. // Return type : void 
  896. // Argument         : int nItemFrom
  897. // Argument         : int nHowMany
  898. // This function will return the real position into listbox.
  899. int CQComboBox::QSnapLoader::Load(int nItemFrom, int nHowMany)
  900. {
  901. int nIF = abs(nItemFrom + (nHowMany < 0 ? nHowMany : 0));
  902. int nHM = abs(nHowMany), nResult = nItemFrom;
  903. CWnd* pWndParentWindowOfCombo = m_pParent->GetParent();
  904. if (nHM = min(nHM, max(0,m_pParent->GetCountItem() - nIF)))
  905. {
  906. //Something must load
  907. ASSERT (nHM != NULL);
  908. SNodeItemsInfo* pNodeNext = m_pFirstNode;
  909. SNodeItemsInfo* pNodePrev = NULL;
  910. // Already the constructor was called
  911. ASSERT (pNodeNext);
  912. //Find the nodes ie pPrevNext->m_nItemLine <= nIF < pPrevNext->m_nItemLine
  913. while (pNodeNext && (nIF >= pNodeNext->m_nItemLine))
  914. {
  915. pNodePrev = pNodeNext;
  916. pNodeNext = pNodeNext->m_pNextNode;
  917. }
  918. // If in the first block , number of items count is equal with total number of items,
  919. // then this function will not be called again. The next function that will
  920. //be called will be AlreadyLoadPartialListBox.
  921. if (m_pFirstNode->m_nCount == m_pParent->GetCountItem())
  922. {
  923. m_pParent->m_fctLoadFunction = m_pParent->AlreadyLoadPartialListBox;
  924. return nItemFrom;
  925. }
  926. LPCTSTR lpszItemLB = NULL;
  927. LPARAM lParam = NULL;
  928. int nFirst = pNodePrev->GetLastLine(), nItem = pNodePrev->GetLastItem();
  929. CListBox* pListBox = m_pParent->GetListBox();
  930. nResult = pNodePrev->GetLastItem();
  931. if (pNodeNext == NULL)
  932. {
  933. // After the prev node do not exist another node.
  934. BOOL bEnd = TRUE;
  935. if (nIF > nFirst)
  936. {
  937. SNodeItemsInfo* sThis = pNodePrev;
  938. pNodePrev = new SNodeItemsInfo(nIF,0, nResult );
  939. sThis->m_pNextNode = pNodePrev;
  940. pNodePrev->m_pPrevNode = sThis;
  941. nFirst = nIF;
  942. bEnd = FALSE;
  943. }
  944. else
  945. {
  946. nResult = pNodePrev->m_nItemLB + nIF - pNodePrev->m_nItemLine;
  947. }
  948. NotifyWindow(pWndParentWindowOfCombo, m_nLoading, m_pParent->m_hWnd, nFirst);
  949. int i = 0;
  950. for (i = 0; (lpszItemLB = m_pParent->Line(nFirst + i, lParam)) && (i < nHM); i++)
  951. {
  952. pListBox->SetItemData(nItem = pListBox->InsertString(nItem, lpszItemLB), lParam);
  953. pNodePrev->m_nCount++;
  954. nItem++;
  955. }
  956. NotifyWindow(pWndParentWindowOfCombo, m_nLoaded, m_pParent->m_hWnd, i);
  957. }
  958. else
  959. {
  960. SNodeItemsInfo* pIncreaseNode = pNodeNext->m_pNextNode;
  961. int nDiff = pNodeNext->m_nItemLine - nFirst;
  962. ASSERT ( nDiff >= 0 );
  963. nItem = nResult; // first item that will be inserted
  964. // {...+..} ___ {...+..}
  965. if (nDiff <= nHM)
  966. {
  967. // The real nHM will be the diference between nHowMany - nDiff
  968. nHM = nDiff;
  969. // Try to restrict these node in only one.
  970. pNodePrev->m_nCount += pNodeNext->m_nCount + nHM;
  971. pNodePrev->m_pNextNode = pNodeNext->m_pNextNode;
  972. delete pNodeNext;
  973. nResult = pNodePrev->m_nItemLB + nIF - pNodePrev->m_nItemLine;
  974. }
  975. else
  976. {
  977. //      nFirst
  978. //        /--- > nHM --
  979. // {...+..} __+________{......}
  980. if (nIF < nFirst)
  981. {
  982. nResult = pNodePrev->m_nItemLB + nIF - pNodePrev->m_nItemLine;
  983. nFirst = pNodePrev->GetLastLine();
  984. pNodePrev->m_nCount += nHM;
  985. pIncreaseNode = pNodeNext;
  986. }
  987. // {......} ______+___ {...+...}
  988. else
  989. if (nIF + nHM >= pNodeNext->m_nItemLine)
  990. {
  991. nHM = pNodeNext->m_nItemLine - nIF;
  992. pNodeNext->m_nItemLine = nIF;
  993. pNodeNext->m_nCount += nHM;
  994. //pNodeNext->m_nItemLB remains constant
  995. nItem = pNodeNext->m_nItemLB;
  996. nFirst = nIF;
  997. nResult = pNodeNext->m_nItemLB;
  998. }
  999. // {......} __+____+___ {......}
  1000. else
  1001. {
  1002. SNodeItemsInfo* sThis = new SNodeItemsInfo(nIF, nHM, nResult );
  1003. sThis->m_pPrevNode = pNodePrev;
  1004. sThis->m_pNextNode = pNodeNext;
  1005. pNodePrev->m_pNextNode = sThis;
  1006. pNodeNext->m_pPrevNode = sThis;
  1007. nFirst = nIF;
  1008. pIncreaseNode = pNodeNext;
  1009. }
  1010. }
  1011. // if some items must insert, do it
  1012. if (nHM > 0)
  1013. {
  1014. NotifyWindow(pWndParentWindowOfCombo, m_nLoading, m_pParent->m_hWnd, nFirst);
  1015. for (int i = 0; i < nHM; i++)
  1016. {
  1017. lpszItemLB = m_pParent->Line(nFirst + i, lParam);
  1018. // while pNodePrev and pNodeNext exist !
  1019. ASSERT (lpszItemLB);
  1020. pListBox->SetItemData(nItem = pListBox->InsertString(nItem, lpszItemLB), lParam);
  1021. nItem++;
  1022. }
  1023. while (pIncreaseNode)
  1024. {
  1025. pIncreaseNode->m_nItemLB += nHM;
  1026. pIncreaseNode = pIncreaseNode->m_pNextNode;
  1027. }
  1028. NotifyWindow(pWndParentWindowOfCombo, m_nLoaded, m_pParent->m_hWnd, nHM);
  1029. }
  1030. }
  1031. }
  1032. return nResult;
  1033. }
  1034. // Function name : CQComboBox::QSnapLoader::GetItemLine
  1035. // Description     : return the real line, converts from nItemLB
  1036. // Return type : int 
  1037. // Argument         : int nItemLB
  1038. int CQComboBox::QSnapLoader::GetItemLine(int nItemLB)
  1039. {
  1040. nItemLB = max(0,nItemLB);
  1041. SNodeItemsInfo* pNodeNext = m_pFirstNode;
  1042. while (pNodeNext && ( pNodeNext->m_nItemLB > nItemLB ))
  1043. pNodeNext = pNodeNext->m_pNextNode;
  1044. return pNodeNext->m_nItemLine  + nItemLB - pNodeNext->m_nItemLB;
  1045. }