复选下拉框CCheckComboBox

来源:互联网 发布:ubuntu没有中文输入法 编辑:程序博客网 时间:2024/05/21 22:31


完整代码请到我的资源里面下载




#if !defined(AFX_CHECKCOMBOBOX_H__66750D93_95DB_11D3_9325_444553540000__INCLUDED_)#define AFX_CHECKCOMBOBOX_H__66750D93_95DB_11D3_9325_444553540000__INCLUDED_#if _MSC_VER > 1000#pragma once#endif // _MSC_VER > 1000class CCheckComboBox : public CBCGPComboBox{public:CCheckComboBox();virtual ~CCheckComboBox();BOOL Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID);// Selects all/unselects the specified itemINT SetCheck(INT nIndex, BOOL bFlag);// Returns checked stateBOOL GetCheck(INT nIndex);// Selects all/unselects allvoid SelectAll(BOOL bCheck = TRUE);protected:// ClassWizard generated virtual function overrides//{{AFX_VIRTUAL(CCheckComboBox)protected:virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);virtual void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct);//}}AFX_VIRTUAL//{{AFX_MSG(CCheckComboBox)afx_msg LRESULT OnCtlColorListBox(WPARAM wParam, LPARAM lParam);afx_msg LRESULT OnGetText(WPARAM wParam, LPARAM lParam);afx_msg LRESULT OnGetTextLength(WPARAM wParam, LPARAM lParam);afx_msg void OnDropDown();//}}AFX_MSGDECLARE_MESSAGE_MAP()protected:// Routine to update the textvoid RecalcText();// The subclassed COMBOLBOX window (notice the 'L')HWND m_hListBox;// The string containing the text to displayCString m_strText;BOOL m_bTextUpdated;// A flag used in MeasureItem, see comments thereBOOL m_bItemHeightSet;};///////////////////////////////////////////////////////////////////////////////{{AFX_INSERT_LOCATION}}// Microsoft Visual C++ will insert additional declarations immediately before the previous line.#endif // !defined(AFX_CHECKCOMBOBOX_H__66750D93_95DB_11D3_9325_444553540000__INCLUDED_)

// CheckComboBox.cpp //// Written by Magnus Egelberg (magnus.egelberg@lundalogik.se)//// Copyright (C) 1999, Lundalogik AB, Sweden. All rights reserved.// //#include "stdafx.h"#include "CheckComboBox.h"#ifdef _DEBUG#define new DEBUG_NEW#undef THIS_FILEstatic char THIS_FILE[] = __FILE__;#endifstatic WNDPROC m_pWndProc = 0;static CCheckComboBox *m_pComboBox = 0;BEGIN_MESSAGE_MAP(CCheckComboBox, CBCGPComboBox)//{{AFX_MSG_MAP(CCheckComboBox)ON_MESSAGE(WM_CTLCOLORLISTBOX, OnCtlColorListBox)ON_MESSAGE(WM_GETTEXT, OnGetText)ON_MESSAGE(WM_GETTEXTLENGTH, OnGetTextLength)ON_CONTROL_REFLECT(CBN_DROPDOWN, OnDropDown)//}}AFX_MSG_MAPEND_MESSAGE_MAP()//// The subclassed COMBOLBOX message handler//extern "C" LRESULT FAR PASCAL ComboBoxListBoxProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam){switch (nMsg) {case WM_RBUTTONDOWN: {// If you want to select all/unselect all using the// right button, remove this ifdef. Personally, I don't really like it#if FALSEif (m_pComboBox != 0) {INT nCount = m_pComboBox->GetCount();INT nSelCount = 0;for (INT i = 0; i < nCount; i++) {if (m_pComboBox->GetCheck(i))nSelCount++;}m_pComboBox->SelectAll(nSelCount != nCount);// Make sure to invalidate this window as wellInvalidateRect(hWnd, 0, FALSE);m_pComboBox->GetParent()->SendMessage(WM_COMMAND, MAKELONG(GetWindowLong(m_pComboBox->m_hWnd, GWL_ID), CBN_SELCHANGE), (LPARAM)m_pComboBox->m_hWnd);}#endifbreak;}// Make the combobox always return -1 as the current selection. This// causes the lpDrawItemStruct->itemID in DrawItem() to be -1// when the always-visible-portion of the combo is drawncase LB_GETCURSEL: {return -1;}case WM_CHAR: {if (wParam == VK_SPACE) {// Get the current selectionINT nIndex = CallWindowProcA(m_pWndProc, hWnd, LB_GETCURSEL, wParam, lParam);CRect rcItem;SendMessage(hWnd, LB_GETITEMRECT, nIndex, (LONG)(VOID *)&rcItem);InvalidateRect(hWnd, rcItem, FALSE);// Invert the check markm_pComboBox->SetCheck(nIndex, !m_pComboBox->GetCheck(nIndex));// Notify that selection has changedm_pComboBox->GetParent()->SendMessage(WM_COMMAND, MAKELONG(GetWindowLong(m_pComboBox->m_hWnd, GWL_ID), CBN_SELCHANGE), (LPARAM)m_pComboBox->m_hWnd);return 0;}break;}case WM_LBUTTONDOWN: {CRect rcClient;GetClientRect(hWnd, rcClient);CPoint pt;pt.x = LOWORD(lParam);pt.y = HIWORD(lParam);if (PtInRect(rcClient, pt)) {INT nItemHeight = SendMessage(hWnd, LB_GETITEMHEIGHT, 0, 0);INT nTopIndex   = SendMessage(hWnd, LB_GETTOPINDEX, 0, 0);// Compute which index to check/uncheckINT nIndex = nTopIndex + pt.y / nItemHeight;CRect rcItem;SendMessage(hWnd, LB_GETITEMRECT, nIndex, (LONG)(VOID *)&rcItem);if (PtInRect(rcItem, pt)) {// Invalidate this windowInvalidateRect(hWnd, rcItem, FALSE);m_pComboBox->SetCheck(nIndex, !m_pComboBox->GetCheck(nIndex));// Notify that selection has changedm_pComboBox->GetParent()->SendMessage(WM_COMMAND, MAKELONG(GetWindowLong(m_pComboBox->m_hWnd, GWL_ID), CBN_SELCHANGE), (LPARAM)m_pComboBox->m_hWnd);}}// Do the default handling now (such as close the popup// window when clicked outside)break;}case WM_LBUTTONUP: {// Don't do anything here. This causes the combobox popup// windows to remain open after a selection has been madereturn 0;}}return CallWindowProc(m_pWndProc, hWnd, nMsg, wParam, lParam);}CCheckComboBox::CCheckComboBox(){m_hListBox       = 0;m_bTextUpdated   = FALSE;m_bItemHeightSet = FALSE;}CCheckComboBox::~CCheckComboBox(){}BOOL CCheckComboBox::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID){// Remove the CBS_SIMPLE and CBS_DROPDOWN styles and add the one I'm designed fordwStyle &= ~0xF;dwStyle |= CBS_DROPDOWNLIST;// Make sure to use the CBS_OWNERDRAWVARIABLE styledwStyle |= CBS_OWNERDRAWVARIABLE;// Use default strings. We need the itemdata to store checkmarksdwStyle |= CBS_HASSTRINGS;return CComboBox::Create(dwStyle, rect, pParentWnd, nID);}LRESULT CCheckComboBox::OnCtlColorListBox(WPARAM wParam, LPARAM lParam) {// If the listbox hasn't been subclassed yet, do so...if (m_hListBox == 0) {HWND hWnd = (HWND)lParam;if (hWnd != 0 && hWnd != m_hWnd) {// Save the listbox handlem_hListBox = hWnd;// Do the subclassingm_pWndProc = (WNDPROC)GetWindowLong(m_hListBox, GWL_WNDPROC);SetWindowLong(m_hListBox, GWL_WNDPROC, (LONG)ComboBoxListBoxProc);}}return DefWindowProc(WM_CTLCOLORLISTBOX, wParam, lParam);}void CCheckComboBox::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) {HDC dc = lpDrawItemStruct->hDC;CRect rcBitmap = lpDrawItemStruct->rcItem;CRect rcText   = lpDrawItemStruct->rcItem;CString strText;// 0 - No check, 1 - Empty check, 2 - CheckedINT nCheck = 0;// Check if we are drawing the static portion of the comboboxif ((LONG)lpDrawItemStruct->itemID < 0) {// Make sure the m_strText member is updatedRecalcText();// Get the textstrText = m_strText;// Don't draw any boxes on this itemnCheck = 0;}// Otherwise it is one of the itemselse {GetLBText(lpDrawItemStruct->itemID, strText);nCheck = 1 + (GetItemData(lpDrawItemStruct->itemID) != 0);TEXTMETRIC metrics;GetTextMetrics(dc, &metrics);rcBitmap.left    = 0;rcBitmap.right   = rcBitmap.left + metrics.tmHeight + metrics.tmExternalLeading + 6;rcBitmap.top    += 1;rcBitmap.bottom -= 1;rcText.left = rcBitmap.right;} if (nCheck > 0) {SetBkColor(dc, GetSysColor(COLOR_WINDOW));SetTextColor(dc, GetSysColor(COLOR_WINDOWTEXT));UINT nState = DFCS_BUTTONCHECK;if (nCheck > 1)nState |= DFCS_CHECKED;// Draw the checkmark using DrawFrameControlDrawFrameControl(dc, rcBitmap, DFC_BUTTON, nState);}if (lpDrawItemStruct->itemState & ODS_SELECTED) {SetBkColor(dc, GetSysColor(COLOR_HIGHLIGHT));SetTextColor(dc, GetSysColor(COLOR_HIGHLIGHTTEXT));}else {SetBkColor(dc, GetSysColor(COLOR_WINDOW));SetTextColor(dc, GetSysColor(COLOR_WINDOWTEXT));}// Erase and drawExtTextOut(dc, 0, 0, ETO_OPAQUE, &rcText, 0, 0, 0);DrawText(dc, ' ' + strText, strText.GetLength() + 1, &rcText, DT_SINGLELINE|DT_VCENTER|DT_END_ELLIPSIS);if ((lpDrawItemStruct->itemState & (ODS_FOCUS|ODS_SELECTED)) == (ODS_FOCUS|ODS_SELECTED))DrawFocusRect(dc, &rcText);}void CCheckComboBox::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct) {CClientDC dc(this);CFont *pFont = dc.SelectObject(GetFont());if (pFont != 0) {TEXTMETRIC metrics;dc.GetTextMetrics(&metrics);lpMeasureItemStruct->itemHeight = metrics.tmHeight + metrics.tmExternalLeading;// An extra height of 2 looks good I think. // Otherwise the list looks a bit crowded...lpMeasureItemStruct->itemHeight += 2;// This is needed since the WM_MEASUREITEM message is sent before// MFC hooks everything up if used in i dialog. So adjust the// static portion of the combo box nowif (!m_bItemHeightSet) {m_bItemHeightSet = TRUE;SetItemHeight(-1, lpMeasureItemStruct->itemHeight);}dc.SelectObject(pFont);}}//// Make sure the combobox window handle is updated since// there may be many CCheckComboBox windows active//void CCheckComboBox::OnDropDown() {m_pComboBox = this;}//// Selects/unselects all items in the list//void CCheckComboBox::SelectAll(BOOL bCheck){INT nCount = GetCount();for (INT i = 0; i < nCount; i++)SetCheck(i, bCheck);}//// By adding this message handler, we may use CWnd::GetText()//LRESULT CCheckComboBox::OnGetText(WPARAM wParam, LPARAM lParam){// Make sure the text is updatedRecalcText();if (lParam == 0)return 0;// Copy the 'fake' window textlstrcpyn((LPWSTR)lParam, m_strText, (INT)wParam);return m_strText.GetLength();}//// By adding this message handler, we may use CWnd::GetTextLength()//LRESULT CCheckComboBox::OnGetTextLength(WPARAM, LPARAM){// Make sure the text is updatedRecalcText();return m_strText.GetLength();}//// This routine steps thru all the items and builds// a string containing the checked items//void CCheckComboBox::RecalcText(){if (!m_bTextUpdated) {CString strText;// Get the list countINT nCount    = GetCount();// Get the list separatorTCHAR szBuffer[10] = {0};GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SLIST, szBuffer, sizeof(szBuffer));CString strSeparator = szBuffer;// If none found, the the ';'if (strSeparator.GetLength() == 0)strSeparator = ';';// Trim extra spacesstrSeparator.TrimRight();// And one...strSeparator += ' ';for (INT i = 0; i < nCount; i++) {if (GetItemData(i)) {CString strItem;GetLBText(i, strItem);if (!strText.IsEmpty())strText += strSeparator;strText += strItem;}}// Set the textm_strText = strText;m_bTextUpdated = TRUE;}}INT CCheckComboBox::SetCheck(INT nIndex, BOOL bFlag){INT nResult = SetItemData(nIndex, bFlag);if (nResult < 0)return nResult;// Signal that the text need updatingm_bTextUpdated = FALSE;// Redraw the windowInvalidate(FALSE);return nResult;}BOOL CCheckComboBox::GetCheck(INT nIndex){return GetItemData(nIndex);}

0 0
原创粉丝点击