Click here to Skip to main content
15,885,914 members
Articles / Programming Languages / VC++
Tip/Trick

Add a Filter Function, Merge Function in MFC Grid Control

Rate me:
Please Sign up or sign in to vote.
5.00/5 (3 votes)
1 Apr 2015CPOL1 min read 22.8K   2.1K   5   2
Add Excel style filter function to Chris Maunder's CGridCtrl

Introduction

I do not speak English well. So this document was created by the Google Translator.

This tip demonstrates how to add "filter cell" and "merge cells" ability to Chris Maunder's MFC Grid control.

The filter cell opens when double clicked.

Background

The filter functions needed to excel in the grid control.

Learn How to Add a Cell Merge and Filter Functions

How to merge cells, see the following links:

CGridCtrl with Merge Cell and Freeze Row, Col Capability

To remove the two, as shown below:

  1. Remove "Ability to do XL Style Freeze Pane"
  2. Remove "The Horizontal Gray Area Removed"

To add a filter, see the following:

C++
// GridCtrl.cpp

void CGridCtrl::OnEndEditCell(int nRow, int nCol, CString str)
{
...
    // Jeong : Extract String
    CStringArray *arrStr = NULL;
    int count = 0;
    if(str.Find(_T(",")) > 0)
    {
        arrStr = Split(str, _T(","));
        count = arrStr->GetCount();
    }

    // Jeong : Apply filter
    if(GetItemState(nRow, nCol) & GVIS_FILTER)
    {
        bool bRowHide = false;
        for (int row=m_nFixedRows; row<m_nRows; row++)
        {
            for (int col=m_nFixedCols; col<m_nCols; col++)
            {
                GRID_ROW* pRow = m_RowData[row];
                if (pRow)
                {
                    CGridCellBase* pRowCell = pRow->GetAt(col);
                    CString strText = pRowCell->GetText();

                    if(nCol == col)
                    {
                        if(count == 0)
                        {
                            if(str != strText && str != _T("ALL"))
                            {
                                bRowHide = true;
                                break;
                            }
                        }
                        else
                        {
                            for(int i=0; i<count; i++)
                            {
                                CString strItem = arrStr->GetAt(i);
                                if(i > 0)
                                    strItem = strItem.Mid(1, strItem.GetLength() - 1);

                                if(strItem == strText || strItem == _T("ALL"))
                                {
                                    bRowHide = false;
                                    break;
                                }
                                else
                                {
                                    bRowHide = true;
                                }
                            }

                            if(bRowHide)
                                break;
                        }
                    }
                }
            }

            if(bRowHide)
            {
                //SetRowHeight(row, 0);
                m_arRowHeights[row] = 0;
                bRowHide = false;
            }
            else
            {
                if(GetRowHeight(row) == 0)
                {
                    m_arRowHeights[row] = m_cellDefault.GetHeight();
                    //SetRowHeight(row, m_cellDefault.GetHeight());
                }
            }
        }

        //SetModified();
        ResetScrollBars();
        Refresh();
    }

    if(arrStr != NULL)
        delete arrStr;
}
C++
BOOL CGridCtrl::IsCellEditable(int nRow, int nCol) const
{
    // Jeong : If the edit is possible GVIS_EDITABLE state
    //return IsEditable() && ((GetItemState(nRow, nCol) & GVIS_READONLY) != GVIS_READONLY);
    return (IsEditable() || GetItemState(nRow, nCol) & GVIS_EDITABLE) && 
				((GetItemState(nRow, nCol) & GVIS_READONLY) != GVIS_READONLY);
}
C++
void CGridCtrl::OnLButtonDblClk(UINT nFlags, CPoint point)
{
...
  // Jeong : Allow edit of fixed row
        //if (cell.row >= m_nFixedRows && IsValid(m_LeftClickDownCell) &&
        //    cell.col >= m_nFixedCols && bInTextArea)
        if (IsValid(m_LeftClickDownCell) && bInTextArea)
        {
            OnEditCell(cell.row, cell.col, pointClickedRel, VK_LBUTTON);
        }
}

Using the Code

Learn how to add a cell merge and filter functions.

Here is a sample code:

C++
BOOL CGridCtrlFilterDlg::OnInitDialog()
{
    m_ctrlGroup.SetXPGroupStyle(CXPGroupBox::XPGB_WINDOW)
       .SetBackgroundColor(RGB(140, 140, 125), RGB(197, 197, 187))
       .SetFontBold(TRUE)
       .SetCaptionTextColor(RGB(255, 255, 255));

    m_ctrlGrid.ModifyStyleEx(WS_EX_CLIENTEDGE, 0, SWP_FRAMECHANGED);

    CRect rect;
    GetClientRect(rect);
    m_OldSize = CSize(rect.Width(), rect.Height());

    int nRow = 1000;
    int nCol = 9;
    int nFilterCol = 2;
    m_RowData = new CArray<CellData>[nRow];
    m_RowData->SetSize(nRow);

    for(int i=0; i<nRow;i++)
    {
        m_RowData[i].SetSize(nCol);

        for(int j=0; j<nCol;j++)
        {   
            CellData data;
            data.row = i;
            data.col = j;
            if(j<8)
                data.data.Format(_T("Person-%d"), i*j);
            else
                data.data.Format(_T("%f"), i*j*0.1);
            m_RowData[i].SetAt(j, data);

        if(j == nFilterCol)
        {
            if (!m_Filter.Lookup(data.data, data.data))
            {
                m_Filter.SetAt(data.data, data.data);
            }
        }
    }

    DrawGrid(m_ctrlGrid, nCol, nRow);

    return TRUE;  // return TRUE  unless you set the focus to a control
}

The way to change the item status to "FILTER".

C++
Item.nFormat = DT_CENTER|DT_WORDBREAK;
Item.strText.Format(_T("Title-01"), col);
UINT state = grid.GetItemState(row, col);
grid.SetItemState(row, col, state | GVIS_FILTER | GVIS_EDITABLE);

This is an example of registering "CheckComboBox".

C++
void CGridCtrlFilterDlg::OnCellCheckCombo2()
{
    int nRow = 0;
    int nCol = 2;

    if (!m_ctrlGrid.SetCellType(nRow, nCol, RUNTIME_CLASS(CGridCellCheckCombo)))
        return;

    m_ctrlGrid.SetItemText(nRow, nCol, _T("Title-02"));

    CStringArray options;
    CArray<BOOL> checks;

    POSITION pos = m_Filter.GetStartPosition();
    int nIndex = 0;
    while(pos != NULL){
        CString strKey;
        CString strValue;
        m_Filter.GetNextAssoc(pos, strKey, strValue);

        if(nIndex == 0)
        {
            options.Add(_T("ALL"));
            checks.Add(TRUE);
        }
        else
        {
            options.Add(strValue);
            checks.Add(FALSE);
        }
        Trace(_T("Filter Data[%d] %s \n"), nIndex++, strValue);
    }

    CGridCellCheckCombo *pCell = (CGridCellCheckCombo*) m_ctrlGrid.GetCell(nRow, nCol);
    pCell->SetOptions(options);
    pCell->SetCheckList(checks);
    pCell->SetStyle(CBS_DROPDOWNLIST); //CBS_DROPDOWN, CBS_DROPDOWNLIST, CBS_SIMPLE
}

Test

  • Tested on Visual Studio 2008, 2010

History

  • 1.0 first release - 2015/03/31

First release version. Added "filter cell" and "merge cells" ability.

Reference Source

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
Korea (Republic of) Korea (Republic of)
Heaven helps those who help themselves.

Comments and Discussions

 
QuestionGridControl Pin
ashwini.sept143-May-15 20:21
ashwini.sept143-May-15 20:21 
GeneralThanks! Pin
Mass Nerder7-Apr-15 3:02
Mass Nerder7-Apr-15 3:02 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.