Chinaunix首页 | 论坛 | 博客
  • 博客访问: 5326483
  • 博文数量: 671
  • 博客积分: 10010
  • 博客等级: 上将
  • 技术积分: 7310
  • 用 户 组: 普通用户
  • 注册时间: 2006-07-14 09:56
文章分类

全部博文(671)

文章存档

2011年(1)

2010年(2)

2009年(24)

2008年(271)

2007年(319)

2006年(54)

我的朋友

分类: C/C++

2007-02-20 17:11:31

最近在编程的时候,我老是碰到这种情况,在列表框中我想在字符串的前面加一个CHECK框,那样,我就可以选择我想要的字符串了。而且,有些时候还需要在一个字符串前面加更多的CHECK框,虽然这对很多人来说是不需要的。所以,我就写了这么一个类,类名是CMultiCheckListBox,这样的话,我上面的问题就会迎刃而解了。在这里面最重要的是一步是怎么在第一个CHECK框加了之后加第2个CHECK框。下面是实现这些的步骤:

    * 添加成员变量,如下:

CMultiCheckListBox m_list; 

    * VC会创建下面的代码(如果没有的话,你就手工添加):

void ccharityreportdlg::dodataexchange(cdataexchange* pdx)
 {
    cdialog::dodataexchange(pdx);
    //{{afx_data_map(ccharityreportdlg)
    ddx_control(pdx, idc_list1, m_list);
    //}}afx_data_map
 }

    * 这一步是添加地2个CHECK框,可以调用类中的setcheck(nindex, ncheck)函数,如下:

m_list.setcheck(nindex,1); 

    * 如果你需要的话,你就要设置地2个CHECK框了,可以调用类中的setmulticheck(nindex, ncheck) 函数,如下:

m_list.setmulticheck(nindex,1); 

    * 如果你想得到第1个CHECK框的状态的话,可以用getcheck(nindex)函数来完成,如下:

m_list.getcheck(nindex); 

    * 如果你想得到第2个CHECK框的状态的话,可以用getmulticheck(nindex)函数来完成,如下:

m_list.multigetcheck(nindex); 

    但是,这个类还是很简单的,它只能添加2个CHECK框,如果有读者有兴趣的话,完全可以把它给扩展了,形成更好的类,下面是类的所有代码,包括.H和.CPP文件:

//下面是H文件
#if !defined(AFX_MULTICHECKLISTBOX_H__D4D62F8F_E758_11D1_AE66_A0B807C10000__INCLUDED_)
#define AFX_MULTICHECKLISTBOX_H__D4D62F8F_E758_11D1_AE66_A0B807C10000__INCLUDED_

#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
// MultiCheckListBox.h : header file
//

/////////////////////////////////////////////////////////////////////////////
// CMultiCheckListBox window

class CMultiCheckListBox : public CCheckListBox
{
// Construction
public:
    CMultiCheckListBox();

// Attributes
public:

// Operations
public:

// Overrides
    // ClassWizard generated virtual function overrides
    //{{AFX_VIRTUAL(CMultiCheckListBox)
    public:
    virtual BOOL OnChildNotify(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pLResult);
    //}}AFX_VIRTUAL

// Implementation
public:
    virtual ~CMultiCheckListBox();
    int  CheckFromPoint(CPoint point, BOOL& bInCheck);
    void InvalidateCheck(int nIndex);
    void SetCheck(int nIndex, int nCheck);
    int  GetCheck(int nIndex);
    int  InMultiCheck(CPoint point, BOOL& bInMultiCheck);
    void InvalidateMultiCheck(int nIndex);
    int  GetMultiCheck(int nIndex);
    void SetMultiCheck(int nIndex, int nCheck);

    // Generated message map functions
protected:
    void PreDrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);

    //{{AFX_MSG(CMultiCheckListBox)
    afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
    //}}AFX_MSG

    DECLARE_MESSAGE_MAP()
};

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}
// Microsoft Developer Studio will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_MULTICHECKLISTBOX_H__D4D62F8F_E758_11D1_AE66_A0B807C10000__INCLUDED_)

//下面是CPP文件
// MultiCheckListBox.cpp : implementation file
//

#include "stdafx.h"
#include "CheckBoxTest.h"
#include "MultiCheckListBox.h"
#include 

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

class _AFX_CHECKLIST_STATE : public CNoTrackObject
{
public:
    _AFX_CHECKLIST_STATE();
    virtual ~_AFX_CHECKLIST_STATE();

    HBITMAP m_hbitmapCheck;
    CSize m_sizeCheck;
};

_AFX_CHECKLIST_STATE::_AFX_CHECKLIST_STATE()
{
    CBitmap bitmap;

    if (afxData.bWin4 || AfxGetCtl3dState()->m_pfnSubclassDlgEx != NULL)
        VERIFY(bitmap.LoadBitmap(AFX_IDB_CHECKLISTBOX_95));
    else
        VERIFY(bitmap.LoadBitmap(AFX_IDB_CHECKLISTBOX_NT));

    BITMAP bm;
    bitmap.GetObject(sizeof (BITMAP), &bm);
    m_sizeCheck.cx = bm.bmWidth / 3;
    m_sizeCheck.cy = bm.bmHeight;
    m_hbitmapCheck = (HBITMAP)bitmap.Detach();
}

_AFX_CHECKLIST_STATE::~_AFX_CHECKLIST_STATE()
{
    if (m_hbitmapCheck != NULL)
        ::DeleteObject(m_hbitmapCheck);
}

EXTERN_PROCESS_LOCAL(_AFX_CHECKLIST_STATE, _afxChecklistState)

/////////////////////////////////////////////////////////////////////////////
// AFX_CHECK_DATA

struct AFX_CHECK_DATA
{
public:
    int m_nCheck;
    BOOL m_bEnabled;
    DWORD m_dwUserData;
    int m_nCheck2;

    AFX_CHECK_DATA()
    {
        m_nCheck = 0;
        m_bEnabled = TRUE;
        m_dwUserData = 0;
        m_nCheck2 = 0;
    };
};

/////////////////////////////////////////////////////////////////////////////
// CMultiCheckListBox

CMultiCheckListBox::CMultiCheckListBox()
{
}

CMultiCheckListBox::~CMultiCheckListBox()
{
}


BEGIN_MESSAGE_MAP(CMultiCheckListBox, CCheckListBox)
    //{{AFX_MSG_MAP(CMultiCheckListBox)
    ON_WM_MEASUREITEM()
    ON_WM_LBUTTONDOWN()
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CMultiCheckListBox message handlers
void CMultiCheckListBox::PreDrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
    _AFX_CHECKLIST_STATE* pChecklistState = _afxChecklistState;

    if ((((LONG)lpDrawItemStruct->itemID) >= 0) &&
       ((lpDrawItemStruct->itemAction & (ODA_DRAWENTIRE | ODA_SELECT)) != 0))
    {
        int cyItem = GetItemHeight(lpDrawItemStruct->itemID);

        CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);

        COLORREF newBkColor = GetSysColor(COLOR_WINDOW);

        BOOL fDisabled = !IsWindowEnabled() || !IsEnabled(lpDrawItemStruct->itemID);
        if ((lpDrawItemStruct->itemState & ODS_SELECTED) && !fDisabled)
            newBkColor = GetSysColor(COLOR_HIGHLIGHT);

        COLORREF oldBkColor = pDC->SetBkColor(newBkColor);

        int nCheck;
        CDC bitmapDC;
        HBITMAP hOldBitmap;
        CRect rectCheck;
        CRect rectItem;
        CRect rectCheckBox;
        if (bitmapDC.CreateCompatibleDC(pDC))
        {
            nCheck = GetCheck(lpDrawItemStruct->itemID);
            hOldBitmap = (HBITMAP)::SelectObject(bitmapDC.m_hDC, pChecklistState->m_hbitmapCheck);

            rectCheck = lpDrawItemStruct->rcItem;
            rectCheck.left += 1;
            rectCheck.top += 1 + max(0, (cyItem - pChecklistState->m_sizeCheck.cy) / 2);
            rectCheck.right = rectCheck.left + pChecklistState->m_sizeCheck.cx;
            rectCheck.bottom = rectCheck.top + pChecklistState->m_sizeCheck.cy;

            rectItem = lpDrawItemStruct->rcItem;
            rectItem.right = rectItem.left + pChecklistState->m_sizeCheck.cx + 2;
            rectItem.right += pChecklistState->m_sizeCheck.cx + 2;

            rectCheckBox = OnGetCheckPosition(rectItem, rectCheck);

            ASSERT(rectCheck.IntersectRect(rectItem, rectCheckBox));
            ASSERT((rectCheck == rectCheckBox) && (rectCheckBox.Size() == pChecklistState->m_sizeCheck));

            CBrush first_brush(newBkColor);
            pDC->FillRect(rectItem, &first_brush);

            pDC->BitBlt(rectCheckBox.left, rectCheckBox.top,
                pChecklistState->m_sizeCheck.cx, pChecklistState->m_sizeCheck.cy, &bitmapDC,
                pChecklistState->m_sizeCheck.cx  * nCheck, 0, SRCCOPY);

            ::SelectObject(bitmapDC.m_hDC, hOldBitmap);
        }

        pDC->SetBkColor(oldBkColor);
    }

    if (lpDrawItemStruct->itemData != 0)
    {
        AFX_CHECK_DATA* pState = (AFX_CHECK_DATA*)lpDrawItemStruct->itemData;
        lpDrawItemStruct->itemData = pState->m_dwUserData;
    }
    
    lpDrawItemStruct->rcItem.left = lpDrawItemStruct->rcItem.left + pChecklistState->m_sizeCheck.cx + 2;
    CCheckListBox::PreDrawItem(lpDrawItemStruct);
}


BOOL CMultiCheckListBox::OnChildNotify(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pLResult) 
{
    switch (message)
    {
    case WM_DRAWITEM:
        ASSERT(pLResult == NULL);       // no return value expected
        PreDrawItem((LPDRAWITEMSTRUCT)lParam);
        break;
    default:
        return CCheckListBox::OnChildNotify(message, wParam, lParam, pLResult);
    }

    return TRUE;
}

PROCESS_LOCAL(_AFX_CHECKLIST_STATE, _afxChecklistState)

void CMultiCheckListBox::SetCheck(int nIndex, int nCheck)
{
    ASSERT(::IsWindow(m_hWnd));

    if (nCheck == 2)
    {
        if (m_nStyle == BS_CHECKBOX || m_nStyle == BS_AUTOCHECKBOX)
            return;
    }

    LRESULT lResult = DefWindowProc(LB_GETITEMDATA, nIndex, 0);
    if (lResult != LB_ERR)
    {

        AFX_CHECK_DATA* pState = (AFX_CHECK_DATA*)lResult;

        if (pState == NULL)
            pState = new AFX_CHECK_DATA;

        pState->m_nCheck2 = nCheck;
        VERIFY(DefWindowProc(LB_SETITEMDATA, nIndex, (LPARAM)pState) != LB_ERR);

        InvalidateCheck(nIndex);
    }
}

int CMultiCheckListBox::GetCheck(int nIndex)
{
    ASSERT(::IsWindow(m_hWnd));

    LRESULT lResult = DefWindowProc(LB_GETITEMDATA, nIndex, 0);
    if (lResult != LB_ERR)
    {
        AFX_CHECK_DATA* pState = (AFX_CHECK_DATA*)lResult;
        if (pState != NULL)
            return pState->m_nCheck2;  // check in first checkbox
    }
    return 0; // The default
}

void CMultiCheckListBox::InvalidateCheck(int nIndex)
{
    CRect rect;
    _AFX_CHECKLIST_STATE* pChecklistState = _afxChecklistState;

    GetItemRect(nIndex, rect);
    rect.right = rect.left + pChecklistState->m_sizeCheck.cx + 2;
    rect.right = rect.left + pChecklistState->m_sizeCheck.cx + 2;
    InvalidateRect(rect, FALSE);
}

void CMultiCheckListBox::SetMultiCheck(int nIndex, int nCheck)
{
    ASSERT(::IsWindow(m_hWnd));

    if (nCheck == 2)
    {
        if (m_nStyle == BS_CHECKBOX || m_nStyle == BS_AUTOCHECKBOX)
            return;
    }

    LRESULT lResult = DefWindowProc(LB_GETITEMDATA, nIndex, 0);
    if (lResult != LB_ERR)
    {

        AFX_CHECK_DATA* pState = (AFX_CHECK_DATA*)lResult;

        if (pState == NULL)
            pState = new AFX_CHECK_DATA;

        pState->m_nCheck = nCheck;
        VERIFY(DefWindowProc(LB_SETITEMDATA, nIndex, (LPARAM)pState) != LB_ERR);

        InvalidateMultiCheck(nIndex);
    }
}

int CMultiCheckListBox::GetMultiCheck(int nIndex)
{
    ASSERT(::IsWindow(m_hWnd));

    LRESULT lResult = DefWindowProc(LB_GETITEMDATA, nIndex, 0);
    if (lResult != LB_ERR)
    {
        AFX_CHECK_DATA* pState = (AFX_CHECK_DATA*)lResult;
        if (pState != NULL)
            return pState->m_nCheck;
    }
    return 0; // The default
}

void CMultiCheckListBox::InvalidateMultiCheck(int nIndex)
{
    CRect rect;
    _AFX_CHECKLIST_STATE* pChecklistState = _afxChecklistState;

    GetItemRect(nIndex, rect);
    rect.left += pChecklistState->m_sizeCheck.cx + 2;
    InvalidateRect(rect, FALSE);
}

int CMultiCheckListBox::CheckFromPoint(CPoint point, BOOL& bInCheck)
{
    // assume did not hit anything
    bInCheck = FALSE;
    int nIndex = -1;

    _AFX_CHECKLIST_STATE* pChecklistState = _afxChecklistState;
    if ((GetStyle() & (LBS_OWNERDRAWFIXED|LBS_MULTICOLUMN)) == LBS_OWNERDRAWFIXED)
    {
        // optimized case for ownerdraw fixed, single column
        int cyItem = GetItemHeight(0);
        if (point.y < cyItem * GetCount())
        {
            nIndex = GetTopIndex() + point.y / cyItem;
            if (point.x < pChecklistState->m_sizeCheck.cx + 2)
                ++bInCheck;
        }
    }
    else
    {
        // general case for ownerdraw variable or multiple column
        for (int i = GetTopIndex(); i < GetCount(); i++)
        {
            CRect itemRect;
            GetItemRect(i, &itemRect);
            if (itemRect.PtInRect(point))
            {
                nIndex = i;
                if (point.x < itemRect.left + pChecklistState->m_sizeCheck.cx + 2)
                    ++bInCheck;
                break;
            }
        }
    }
    return nIndex;
}

int CMultiCheckListBox::InMultiCheck(CPoint point, BOOL& bInMultiCheck)
{
    // assume did not hit anything
    bInMultiCheck = FALSE;
    int nIndex = -1;

    _AFX_CHECKLIST_STATE* pChecklistState = _afxChecklistState;
    if ((GetStyle() & (LBS_OWNERDRAWFIXED|LBS_MULTICOLUMN)) == LBS_OWNERDRAWFIXED)
    {
        // optimized case for ownerdraw fixed, single column
        int cyItem = GetItemHeight(0);
        if (point.y < cyItem * GetCount())
        {
            nIndex = GetTopIndex() + point.y / cyItem;
            if (point.x < pChecklistState->m_sizeCheck.cx + 2 + (pChecklistState->m_sizeCheck.cx + 2))
                ++bInMultiCheck;
        }
    }
    else
    {
        // general case for ownerdraw variable or multiple column
        for (int i = GetTopIndex(); i < GetCount(); i++)
        {
            CRect itemRect;
            GetItemRect(i, &itemRect);
            if (itemRect.PtInRect(point))
            {
                nIndex = i;
                if (point.x < itemRect.left + pChecklistState->m_sizeCheck.cx + 2)
                    ++bInMultiCheck;
                break;
            }
        }
    }
    return nIndex;
}

void CMultiCheckListBox::OnLButtonDown(UINT nFlags, CPoint point) 
{
    SetFocus();

    // determine where the click is
    BOOL bInCheck;
    BOOL bInMultiCheck;
    int nIndex = CheckFromPoint(point, bInCheck);
    int n2Index = InMultiCheck(point, bInMultiCheck);

    // if the item is disabled, then eat the click
    if (!IsEnabled(nIndex))
        return;

    if (m_nStyle != BS_CHECKBOX && m_nStyle != BS_3STATE)
    {
        // toggle check mark automatically if check mark was hit
        if (bInCheck)
        {
            CWnd* pParent = GetParent();
            ASSERT_VALID(pParent);

            int nModulo = (m_nStyle == BS_AUTO3STATE) ? 3 : 2;
            int nCheck = GetCheck(nIndex);
            nCheck = (nCheck == nModulo) ? nCheck - 1 : nCheck;
            SetCheck(nIndex, (nCheck + 1) % nModulo);

            InvalidateCheck(nIndex);

            CListBox::OnLButtonDown(nFlags, point);

            // Inform of check
            pParent->SendMessage(WM_COMMAND,
                MAKEWPARAM(GetDlgCtrlID(), CLBN_CHKCHANGE),
                (LPARAM)m_hWnd);
            return;
        }
        if (bInMultiCheck)
        {
            CWnd* pParent = GetParent();
            ASSERT_VALID(pParent);
            int nModulo = (m_nStyle == BS_AUTO3STATE) ? 3 : 2;
            int nCheck = GetMultiCheck(nIndex);
            nCheck = (nCheck == nModulo) ? nCheck - 1 : nCheck;
            SetMultiCheck(nIndex, (nCheck + 1) % nModulo);

            CListBox::OnLButtonDown(nFlags, point);

            // Inform of check
            pParent->SendMessage(WM_COMMAND,
                MAKEWPARAM(GetDlgCtrlID(), CLBN_CHKCHANGE),
                (LPARAM)m_hWnd);
            return;
        }
    }

    // do default listbox selection logic
    CListBox::OnLButtonDown(nFlags, point);
}

  译于2001年9月12号。我没有看完全部的代码,我希望读者能把它给看完,那样会对你更有好处。


阅读(1833) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~