www.gusucode.com > vc++在下拉选框中使用树形菜单源码程序 > vc++在下拉选框中使用树形菜单源码程序\code\CheckComboBox.cpp
//####################################################################################### //## CheckComboBox.cpp : implementation file //####################################################################################### #include "stdafx.h" #include "sample.h" #include "CheckComboBox.h" //Download by http://www.NewXing.com #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif //## ==================================================================================== WNDPROC CCheckComboBox::m_parentWndProc = NULL; CWnd* CCheckComboBox::m_pwndActiveDropDown = NULL; CCheckComboBox* CCheckComboBox::m_pwndActiveCheckComboBox = NULL; CRect CCheckComboBox::m_rcParentRect = CRect(0, 0, 0, 0); //####################################################################################### IMPLEMENT_DYNAMIC(CCheckComboBox, CButton) //## ==================================================================================== CCheckComboBox::CCheckComboBox() { //## INITIALIZE m_pwndTree = NULL; m_parentWndProc = NULL; m_pwndActiveCheckComboBox = NULL; m_nDroppedWidth = DROPPED_WIDTH_NOT_SET; } //## ==================================================================================== CCheckComboBox::~CCheckComboBox() { //## HIDE ActiveDropDown HideActiveDropDown(); //## UNINTERCEPT UnInterceptParentWndProc(); //## DESTROY Tree if (m_pwndTree){ m_pwndTree->ShowWindow( SW_HIDE ); delete m_pwndTree; m_pwndTree = NULL; } } //## ==================================================================================== void CCheckComboBox::OnDestroy() { //## CALL Parent CButton::OnDestroy(); //## HIDE ActiveDropDown HideActiveDropDown(); //## UNINTERCEPT UnInterceptParentWndProc(); } //####################################################################################### BEGIN_MESSAGE_MAP(CCheckComboBox, CButton) ON_WM_DESTROY() ON_WM_LBUTTONDOWN() ON_WM_LBUTTONDBLCLK() ON_WM_GETDLGCODE() ON_WM_KILLFOCUS() END_MESSAGE_MAP() //####################################################################################### void CCheckComboBox::OnLButtonDown(UINT nFlags, CPoint point) { //## CALL Parent CButton::OnLButtonDown(nFlags, point); //## SHOW Tree ShowDropWnd(); } //## ==================================================================================== void CCheckComboBox::OnLButtonDblClk(UINT nFlags, CPoint point) { //## CALL Parent CButton::OnLButtonDown(nFlags, point); //## SHOW Tree ShowDropWnd(); } //## ==================================================================================== LRESULT CCheckComboBox::WindowProc( UINT message, WPARAM wParam, LPARAM lParam ) { //## CATCH DropDown Keys switch (message){ case WM_KEYDOWN: case WM_SYSKEYDOWN: switch ((int) wParam){ case VK_F4: ShowDropWnd(); return NULL; //## INTERCEPT case VK_DOWN: case VK_UP: if (message == WM_SYSKEYDOWN) ShowDropWnd(); return NULL; //## INTERCEPT case VK_SPACE: return NULL; //## INTERCEPT } } //## CALL Parent return CButton::WindowProc(message, wParam, lParam); } //## ==================================================================================== BOOL CCheckComboBox::PreTranslateMessage(MSG* pMsg) { //## INTERCEPT Keys => send them to tree if ((pMsg->message >= WM_KEYFIRST) && (pMsg->message <= WM_KEYLAST)) if(m_pwndActiveDropDown){ m_pwndActiveDropDown->SendMessage( pMsg->message, pMsg->wParam, pMsg->lParam); ((CCheckTreeCtrl*)m_pwndActiveDropDown)->UpdateToState(); return FALSE; } //## PROCESS ToolTip InitToolTip(); m_ToolTip.RelayEvent(pMsg); return CButton::PreTranslateMessage(pMsg); } //####################################################################################### void CCheckComboBox::DrawItem( LPDRAWITEMSTRUCT lpDrawItemStruct ) { //## GET CDC CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC); //## FRAME CRect rc = lpDrawItemStruct->rcItem; pDC->DrawEdge( rc, EDGE_SUNKEN, BF_TOP | BF_LEFT | BF_BOTTOM | BF_RIGHT ); //## DRAW white BK rc.DeflateRect(2, 2); static CBrush brWindow(GetSysColor(COLOR_WINDOW)); static CBrush brBtnFace(GetSysColor(COLOR_BTNFACE)); static CBrush brBtnShadow(GetSysColor(COLOR_BTNSHADOW)); if (IsWindowEnabled()) pDC->FillRect(&rc, &brWindow); else pDC->FillRect(&rc, &brBtnFace); //## COMPUTE Button Rect CRect rcButton = rc; rcButton.left = rcButton.right - DROP_BUTTON_WIDTH; if (rcButton.left < rc.left) rcButton.left = rc.left; //## COMPUTE Caption Rect CRect rcCaption = rc; rcCaption.right = rcButton.left - 1; if (rcCaption.right < rcCaption.left) rcCaption.right = rcCaption.left; //## FOCUS rcCaption.DeflateRect(1, 1); if (lpDrawItemStruct->itemState & ODS_FOCUS) pDC->DrawFocusRect(rcCaption); rcCaption.DeflateRect(2, 1); //## GET Caption CString strText; GetWindowText(strText); //## DRAW Caption pDC->SetBkColor( (IsWindowEnabled()) ? GetSysColor(COLOR_WINDOW) : GetSysColor(COLOR_BTNFACE) ); COLORREF crOldColor = SetTextColor(lpDrawItemStruct->hDC, RGB(0, 0, 0)); DrawText(lpDrawItemStruct->hDC, strText, strText.GetLength(), &rcCaption, DT_SINGLELINE | DT_VCENTER ); SetTextColor(lpDrawItemStruct->hDC, crOldColor); //## GET Button Style UINT uStyle = DFCS_BUTTONPUSH; if (lpDrawItemStruct->itemState & ODS_SELECTED) uStyle |= DFCS_PUSHED; //## DRAW Button if (lpDrawItemStruct->itemState & ODS_SELECTED){ pDC->FrameRect(rcButton, &brBtnShadow); rcButton.DeflateRect(1, 1); pDC->FillRect(&rcButton, &brBtnFace); rcButton.DeflateRect(1, 3, 0, 0); }else{ pDC->FrameRect(rcButton, &brBtnFace); rcButton.DeflateRect(1, 1, 0, 0); DrawFrameControl(lpDrawItemStruct->hDC, &rcButton, DFC_BUTTON, uStyle); } //## DRAW Arrow static CPen penBlack(PS_SOLID, 1, RGB(0, 0, 0)); static CPen penBtnShadow(PS_SOLID, 1, GetSysColor(COLOR_BTNSHADOW)); CPen* ppenOld; if (IsWindowEnabled()) ppenOld = pDC->SelectObject(&penBlack); else ppenOld = pDC->SelectObject(&penBtnShadow); for(long i=0; i<4; i++){ pDC->MoveTo( rcButton.left + 3 + i, rcButton.top + rcButton.Height()/2 - 2 + i); pDC->LineTo( rcButton.left + 3 + 7 - i, rcButton.top + rcButton.Height()/2 - 2 + i); if (!IsWindowEnabled()) pDC->SetPixel(rcButton.left + 3 + 7 - i, rcButton.top + rcButton.Height()/2 - 2 + i + 1, 0xFFFFFF); } pDC->SelectObject(ppenOld); } //####################################################################################### void CCheckComboBox::AddString(LPCTSTR lpszString, long nID, long nLevel) { //## IF is the first item => add root if (m_Data.GetSize() == 0) m_Data.AddString(lpszString, INVALID_ID, ROOT_LEVEL); //## ADD m_Data.AddString(lpszString, nID, nLevel); } //## ==================================================================================== void CCheckComboBox::CheckAll(BOOL bCheck) { m_Data.CheckAll(bCheck); UpdateCaption(); } //## ==================================================================================== void CCheckComboBox::SetCheck(long nID, BOOL bCheck) { m_Data.SetCheck(nID, bCheck); UpdateCaption(); } //## ==================================================================================== BOOL CCheckComboBox::GetCheck(long nID) { return m_Data.GetCheck(nID); } //## ==================================================================================== int CCheckComboBox::GetCount() { return m_Data.GetSize(); } //## ==================================================================================== CString CCheckComboBox::GetCheckedIDs() { return m_Data.GetCheckedIDs(); } CString CCheckComboBox::GetCheckedTexts() { return m_Data.GetCheckedTexts(); } //## ==================================================================================== void CCheckComboBox::UpdateCaption() { //## CAPTION CString str = m_Data.GetCheckedTexts(); SetWindowText(str); //## ASSERT if (!::IsWindow(m_ToolTip.m_hWnd)) InitToolTip(); if (!::IsWindow(m_ToolTip.m_hWnd)) return; //## TOOLTIP m_ToolTip.SetMaxTipWidth( TOOLTIP_MAX_WIDTH ); if (str.GetLength() > TOOLTIP_MAX_CHARACTERS) str = str.Mid(0, (TOOLTIP_MAX_CHARACTERS-3)) + "..."; SetToolTipText( str ); } //####################################################################################### void CCheckComboBox::SetImageList(CImageList *pimgList) { //## SET ImageList m_imgList.Create( pimgList ); } //## ==================================================================================== CImageList* CCheckComboBox::GetImageList() { //## ASSERT if ((HIMAGELIST)m_imgList) return &m_imgList; return NULL; } //####################################################################################### void CCheckComboBox::ShowDropWnd() { //## ASSERT if (!m_pwndTree) CreateDropWnd(); if (!m_pwndTree) return; //## PLACE Tree PlaceDropWnd(); //## DROP Drop( !IsDropped() ); } //## ==================================================================================== void CCheckComboBox::CreateDropWnd() { //## ASSERT if (m_pwndTree) return; //## CREATE Tree m_pwndTree = new CCheckTreeCtrl; m_pwndTree->CreateEx( WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR | WS_EX_TOOLWINDOW, WC_TREEVIEW, NULL, WS_CHILD | WS_BORDER | WS_CLIPSIBLINGS | WS_OVERLAPPED | TVS_HASBUTTONS | TVS_HASLINES | TVS_CHECKBOXES | TVS_DISABLEDRAGDROP | TVS_SHOWSELALWAYS | TVS_FULLROWSELECT, CRect(0, 0, 0, 0), GetDesktopWindow(), 0x3E8, NULL); //## MOVE on top m_pwndTree->SetWindowPos(&CWnd::wndTopMost, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); //## SET Parent m_pwndTree->SetParentCombo( this ); //## ATTACH ImageList if (GetImageList()) m_pwndTree->SetImageList( GetImageList(), TVSIL_NORMAL ); //## POPULATE m_pwndTree->Populate(); } //## ==================================================================================== void CCheckComboBox::PlaceDropWnd() { //## ASSERT if (!m_pwndTree) CreateDropWnd(); if (!m_pwndTree) return; //## GET ComboRect CRect rc; GetWindowRect(&rc); //## MOVE Tree m_pwndTree->MoveWindow(rc.left, rc.bottom, GetDroppedWidth(), DROPDOWN_HEIGHT); } //## ==================================================================================== BOOL CCheckComboBox::IsDropped() { //## ASSERT if (!m_pwndTree) return FALSE; //## RETURN return ( m_pwndTree->IsWindowVisible() ); } //## ==================================================================================== void CCheckComboBox::Drop(BOOL bDrop) { //## ASSERT if (!m_pwndTree) return; //## DROP/UNDROP if (bDrop){ //## ASSERT HideActiveDropDown(); //## INTERCEPT parent messages if (!m_parentWndProc) InterceptParentWndProc(); //## STRANGE (I do not know why... but without an image list, the following lines are needed) if (!(HIMAGELIST)m_imgList){ m_pwndTree->ShowWindow( SW_SHOW ); m_pwndTree->UpdateFromState(); } //## UPDATE m_pwndTree->UpdateFromState(); //## SHOW Window m_pwndTree->ShowWindow( SW_SHOW ); m_pwndTree->SetFocus(); //## SET Active DropDown m_pwndActiveDropDown = m_pwndTree; m_pwndActiveCheckComboBox = this; //## TOOLTIP SetToolTipText( "" ); //## TO BE SURE (if our combo is in a FormView) if (this->GetParent()) this->GetParent()->GetWindowRect( &m_rcParentRect ); }else{ //## ASSERT HideActiveDropDown(); //## HIDE Window m_pwndTree->ShowWindow( SW_HIDE ); //## CAPTION UpdateCaption(); } } //## ==================================================================================== void CCheckComboBox::HideActiveDropDown() { //## ASSERT if (!m_pwndActiveDropDown) return; //## HIDE Window m_pwndActiveDropDown->ShowWindow( SW_HIDE ); m_pwndActiveDropDown = NULL; //## CAPTION if (m_pwndActiveCheckComboBox){ m_pwndActiveCheckComboBox->UpdateCaption(); m_pwndActiveCheckComboBox = NULL; } } //####################################################################################### void CCheckComboBox::InterceptParentWndProc() { //## ASSERT if (m_parentWndProc) return; //## ASSERT CWnd *pwndParent = GetParent(); if (!pwndParent) return; if (!pwndParent->GetSafeHwnd()) return; //## GET Parent WinProc & SET our function m_parentWndProc = (WNDPROC)::SetWindowLong(pwndParent->GetSafeHwnd(), GWL_WNDPROC, (long)(WNDPROC)ParentWindowProc); } //## ==================================================================================== void CCheckComboBox::UnInterceptParentWndProc() { //## ASSERT if (!m_parentWndProc) return; //## ASSERT CWnd *pwndParent = GetParent(); if (!pwndParent) return; if (!pwndParent->GetSafeHwnd()) return; //## SET Parent WinProc = UNINTERCEPT (WNDPROC)::SetWindowLong(pwndParent->GetSafeHwnd(), GWL_WNDPROC, (long)(WNDPROC)m_parentWndProc); m_parentWndProc = NULL; } //## ==================================================================================== LRESULT CALLBACK CCheckComboBox::ParentWindowProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam) { //## CHECK Message switch (nMsg){ case WM_COMMAND: case WM_SYSCOMMAND: case WM_SYSKEYDOWN: case WM_LBUTTONDOWN: case WM_NCLBUTTONDOWN: case WM_WINDOWPOSCHANGING: case WM_WINDOWPOSCHANGED: //## FILTER Messages if (IsMsgOK(hWnd, nMsg,/* wParam,*/ lParam)) break; //## HIDE Active DropDown HideActiveDropDown(); break; case WM_PAINT: //## TO BE SURE (if our combo is in a FormView) if (m_pwndActiveCheckComboBox) if (m_pwndActiveCheckComboBox->GetParent()){ CRect rcParent; m_pwndActiveCheckComboBox->GetParent()->GetWindowRect( &rcParent ); if ((rcParent.top != m_rcParentRect.top) || (rcParent.left != m_rcParentRect.left)) HideActiveDropDown(); } break; } //## CALL Parent if(!m_parentWndProc) return NULL; return CallWindowProc( m_parentWndProc, hWnd, nMsg, wParam, lParam ); } //## ==================================================================================== BOOL CCheckComboBox::IsMsgOK(HWND hWnd, UINT nMsg, /*WPARAM wParam,*/ LPARAM lParam) { //## ASSERT if (!hWnd) return FALSE; if (nMsg != WM_COMMAND) return FALSE; if (!m_pwndActiveDropDown) return FALSE; if ((HWND)lParam != m_pwndActiveCheckComboBox->GetSafeHwnd()) return FALSE; //## GET DropDownRect CRect rc; m_pwndActiveCheckComboBox->GetWindowRect( rc ); //## GET MousePos CPoint pt; ::GetCursorPos( &pt ); //## CHECK is in rect if (pt.x < rc.left) return FALSE; if (pt.x > rc.right) return FALSE; if (pt.y < rc.top) return FALSE; if (pt.y > rc.bottom) return FALSE; //## FINALLY return TRUE; } //## ==================================================================================== UINT CCheckComboBox::OnGetDlgCode() { return DLGC_WANTARROWS | DLGC_WANTCHARS | CButton::OnGetDlgCode(); } //####################################################################################### void CCheckComboBox::OnKillFocus(CWnd* pNewWnd) { //## CALL Parent CButton::OnKillFocus(pNewWnd); //## HIDE Active DropDown HideActiveDropDown(); } //####################################################################################### void CCheckComboBox::InitToolTip() { if (m_ToolTip.m_hWnd == NULL){ try{ m_ToolTip.Create(this); m_ToolTip.Activate(FALSE); }catch(...){}; } } //## ==================================================================================== void CCheckComboBox::SetToolTipText(int nId, BOOL bActivate) { //## LOAD String CString strText; strText.LoadString(nId); //## SET Tooltip if (strText.IsEmpty() == FALSE) SetToolTipText(strText, bActivate); } //## ==================================================================================== void CCheckComboBox::SetToolTipText(CString strText, BOOL bActivate) { //## INITIALIZE ToolTip InitToolTip(); //## IF there is no tooltip defined then add it if (m_ToolTip.GetToolCount() == 0) { CRect rectBtn; GetClientRect(rectBtn); m_ToolTip.AddTool(this, (LPCTSTR)strText, rectBtn, 1); } //## SET text for tooltip m_ToolTip.UpdateTipText((LPCTSTR)strText, this, 1); m_ToolTip.Activate(bActivate); } //####################################################################################### long CCheckComboBox::GetDroppedWidth() { //## ASSERT if (m_nDroppedWidth != DROPPED_WIDTH_NOT_SET) return m_nDroppedWidth; if (!m_hWnd) return DROPPED_WIDTH_NOT_SET; //## GET ComboRect CRect rc; GetWindowRect(&rc); //## SET, RETURN DroppedWidth m_nDroppedWidth = rc.Width(); return m_nDroppedWidth; } //## ==================================================================================== void CCheckComboBox::SetDroppedWidth(long nWidth) { m_nDroppedWidth = nWidth; } //#######################################################################################