Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / VisualC++

Add a Filter Function, Merge Function in MFC Grid Control

5.00/5 (3 votes)
1 Apr 2015CPOL1 min read 23.5K   2.2K  
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)