MFC Feature Pack Tutorial – Part 3 – CMFCPropertyGridCtrl

 

What is this CMFCPropertyGridCtrl?

It’s a cool new control found in MFC feature pack. Those who’ve used VB, C#, must be familiar with this control. It’s the good old vb property control. This is how the old vb control looked.

It can be called a two column list control with a tree embedded inside it. But it is not just that, here are some properties of this new control…

  1. Allows custom properties
  2. Allows custom controls inside property values
  3. Allows nested properties
  4. Allows font properties
  5. Allows color properties
  6. Fires events when a property is updated
  7. Allows grouping of properties
  8. VS look and feel
  9. Allows custom colors
  10. Allows feedback for properties that has changed, changes text style to bold
  11. One touch expand of all nodes
  12. Allows a toolbar to be placed at the top
  13. Allows boolean properties

So what’s the class name of this new control?

Of course it’s CMFCPropertyGridCtrl.

Basic architecture of CMFCPropertyGridCtrl

Base class of all properties in this control is called CMFCPropertyGridProperty. Derive from this class to add on more properties. Each CMFCPropertyGridProperty can take additional sub properties which in turn again can take further sub properties, which in turn can take further sub properties… So kinda makes a tree structure.

All items get removed in OnDestroy of this control. Every property get’s “delete”d which turn calls CMFCPropertyGridProperty’s destructor which in turn calls child properties destructor which again in turn calls any futher child properties destructor and this goes on for every property in the control.

All properties must be allocated on the heap using “new”. An exception to this rule are nested child properties of CMFCPropertyGridProperty which can be on the stack but make sure that you remove them before the call to OnDestroy of this control, since delete get’s applied to every property and it’s sub property. Also make sure that such an object has sufficient life time. There is an option in CMFCPropertyGridProperty::RemoveSubItem to prevent “delete”ing of such properties.

Adding properties to CMFCPropertyGridCtrl

To add a property to this control we use the function called CMFCPropertyGridCtrl::AddProperty, note that properties should be dynamically allocated, because CMFCPropGridCtrl::OnDestroy uses delete to free properties.

Deleting properties

To remove a property we use the function called CMFCPropertyGridCtrl::DeleteProperty. Note what was said earlier, all properties should be dynamically allocated. Also note that only properties that was directly given to this control will be deleted, sub properties should be deleted via their parent property class only.

Adding sub properties

To add a sub property call CMFCPropertyGridProperty::AddSubItem with the address of the new sub item. It’s up to you to decide whether this sub property should be on the heap or on the stack. If it’s on the stack then make sure you remove such an item before the call to main property grid control’s OnDestroy.

Removing sub properties

All sub properties get removed when the control is destroyed but such properties should be allocated on the heap.

To remove sub properties in between call CMFCPropertyGridProperty::RemoveSubItem. It takes a pointer reference to the item that is to be deleted and optional last boolean parameter which if set will delete given pointer, else won’t.

Show us some code man!

Ok don’t loose your cool, enough of preaching now it’s all practical stuff mate. 😛

Here is a function which sets up a simple property grid control. With some properties and some nested properties.

void CPropertyGridCtrlTestDlg::InitPropGrid()
{
    // Switch look and feel to office 2007 style
    CMFCVisualManagerOffice2007::SetStyle( CMFCVisualManagerOffice2007::Office2007_ObsidianBlack );
    CMFCVisualManager::SetDefaultManager( RUNTIME_CLASS( CMFCVisualManagerOffice2007 ));

    CRect Rect;
    m_wndPropListLocation.GetClientRect( Rect );
    m_wndPropListLocation.MapWindowPoints( this, &Rect );

    m_wndPropList.Create( WS_CHILD | WS_BORDER | WS_VISIBLE | WS_TABSTOP, Rect, this, 1231 );
    m_wndPropList.EnableHeaderCtrl( TRUE, _T( "Nibu's Property" ), _T( "Nibu's Value" ));
    m_wndPropList.SetVSDotNetLook( TRUE );

    // Create a property group for appearance
    CMFCPropertyGridProperty * pGroupTest = new CMFCPropertyGridProperty( _T( "Group Test" ) );
    m_wndPropList.AddProperty( pGroupTest );

    const int MaxNesting = 5;
    CMFCPropertyGridProperty *pParent = pGroupTest;
    for( int Index = 0; Index < MaxNesting; ++Index )
    {
        CString Text;
        Text.Format( _T( "Nesting %d" ), Index + 1 );

        CMFCPropertyGridProperty* pParentTemp = new CMFCPropertyGridProperty( Text );

        // Display's a combo with options as True, False, Cool!
        COleVariant Bool((short)VARIANT_FALSE, VT_BOOL);
        pParent->AddSubItem(new CMFCPropertyGridProperty(_T("Bool test"), Bool, _T("Testing kids")));
        pParent->AddSubItem( pParentTemp );
        pParent = pParentTemp;
    }

    // A font property
    LOGFONT lf = { 0 };
    GetFont()->GetLogFont( &lf );
    CMFCPropertyGridFontProperty* pFntProp = new CMFCPropertyGridFontProperty( _T( "Font (Font dialog comes up)" ), lf );
    pGroupTest->AddSubItem( pFntProp );

    // Combo property, set sub options which are displayed in a combo
    CMFCPropertyGridProperty* pCmbProp = new CMFCPropertyGridProperty(_T("Border (A combo box)"), _T("Dialog Frame"), _T("One of: None, Thin, Resizable, or Dialog Frame"));
    pCmbProp->AddOption(_T("None"));
    pCmbProp->AddOption(_T("Thin"));
    pCmbProp->AddOption(_T("Resizable"));
    pCmbProp->AddOption(_T("Dialog Frame"));
    pCmbProp->AllowEdit(FALSE);
    pGroupTest->AddSubItem( pCmbProp );

    // A folder browse dialog property
    CMFCPropertyGridFileProperty* pFolderProp = new CMFCPropertyGridFileProperty( _T( "Select folder (Browse for folder dialog)" ), _T( "C:\\Windows" ));
    pGroupTest->AddSubItem( pFolderProp );

    // A file open dialog property
    CMFCPropertyGridFileProperty* pFileProp = new CMFCPropertyGridFileProperty( _T( "Select file (Open file dialog)" ), TRUE, _T( "C:\\Windows" ));
    pGroupTest->AddSubItem( pFileProp );

    // A masked edit control for phone number
    pGroupTest->AddSubItem( new CMFCPropertyGridProperty(_T("Phone (Masked edit)"), _T("(123) 123-12-12"), _T("Enter a phone number"), 0, _T(" ddd  ddd dd dd"), _T("(___) ___-__-__")));

    // A color property
    CMFCPropertyGridColorProperty* pColorProp = new CMFCPropertyGridColorProperty( _T( "Select color" ), RGB( 120, 198, 250 ));
    pGroupTest->AddSubItem( pColorProp );

    // Set custom colors for property grid
    m_wndPropList.SetCustomColors(RGB(228, 243, 254), RGB(46, 70, 165), RGB(200, 236, 209), RGB(33, 102, 49), RGB(255, 229, 216), RGB(128, 0, 0), RGB(159, 159, 255));
}

And the output looks like this…

  24 Responses to “MFC Feature Pack Tutorial – Part 3 – CMFCPropertyGridCtrl”

  1. how can i set different colors for each row text?

  2. Hi,
    Sorry I’m a beginner at MFC programming.
    May I ask from where did you get the variable m_wndPropListLocation?
    I wanna test the code thx.

  3. Hi,
    I used CMFCPropertyGridCtrl in propety list with edit box( ex: Width 10, height 20 )
    I used Spincontrol . Now i want to give a check for Float values also
    Right now it accepts only integer values.

    how to give float value check in CMFCGridcontrol?

  4. Hi

    I thank you for your article! But I have a question …

    With CMFCColoredButton it allows you to use SetColorName. This is great as I can assign a group of colours to the control and then give them names.

    But when I use CMFCPropertyGridColorProperty it does not seem to let me do the same thing.

    Andrew

    • I’ve got to check this Andrew. Not sure when I’ll be able to but if you have a sample that I can start working on that will get me started.

      • Hi

        Well, this code creates a pallette. You could copy it:

        CPalette* CMyMFCColorButton::CreatePalette()
        {
        CPalette *pPalette = NULL;
        CArray aryColours;

        aryColours.Add(PALETTERGB(0x00, 0x00, 0x00));
        aryColours.Add(PALETTERGB(0xFF, 0xFF, 0x00));
        aryColours.Add(PALETTERGB(0xFF, 0xFF, 0xFF));
        aryColours.Add(PALETTERGB(0x80, 0x00, 0x00));
        aryColours.Add(PALETTERGB(0x00, 0x80, 0x00));
        aryColours.Add(PALETTERGB(0x80, 0x80, 0x00));
        aryColours.Add(PALETTERGB(0x00, 0x00, 0x80));
        aryColours.Add(PALETTERGB(0x80, 0x00, 0x80));
        aryColours.Add(PALETTERGB(0x00, 0x80, 0x80));
        aryColours.Add(PALETTERGB(0x80, 0x80, 0x80));
        aryColours.Add(PALETTERGB(0xC0, 0xC0, 0xC0));
        aryColours.Add(PALETTERGB(0xFF, 0x00, 0x00));
        aryColours.Add(PALETTERGB(0x00, 0xFF, 0x00));
        aryColours.Add(PALETTERGB(0x00, 0x00, 0xFF));
        aryColours.Add(PALETTERGB(0xFF, 0x00, 0xFF));
        aryColours.Add(PALETTERGB(0x00, 0xFF, 0xFF));
        aryColours.Add(PALETTERGB(0xFF, 0xC0, 0x00));

        LOGPALETTE* pLogPalette = (LOGPALETTE*) new BYTE[sizeof(LOGPALETTE) +
        (aryColours.GetCount() * sizeof(PALETTEENTRY))];
        pLogPalette->palNumEntries = (WORD)aryColours.GetCount();
        pLogPalette->palVersion = 0x300;

        for (int iColour = 0; iColour palPalEntry[iColour].peRed = GetRValue(currentColor);
        pLogPalette->palPalEntry[iColour].peGreen = GetGValue(currentColor);
        pLogPalette->palPalEntry[iColour].peBlue = GetBValue(currentColor);
        }

        pPalette = new CPalette();
        if (pPalette != NULL)
        pPalette->CreatePalette(pLogPalette);

        delete[]pLogPalette;

        return pPalette;
        }

        Pass that object in to your colour property.

        Now, with a regular MFC colour button you can also do:

        CList m_Colours;
        m_Colours.AddTail(PALETTERGB(0x00, 0x00, 0x00));
        m_Colours.AddTail(PALETTERGB(0xFF, 0xFF, 0x00));
        m_Colours.AddTail(PALETTERGB(0xFF, 0xFF, 0xFF));
        m_Colours.AddTail(PALETTERGB(0x80, 0x00, 0x00));
        m_Colours.AddTail(PALETTERGB(0x00, 0x80, 0x00));
        m_Colours.AddTail(PALETTERGB(0x80, 0x80, 0x00));
        m_Colours.AddTail(PALETTERGB(0x00, 0x00, 0x80));
        m_Colours.AddTail(PALETTERGB(0x80, 0x00, 0x80));
        m_Colours.AddTail(PALETTERGB(0x00, 0x80, 0x80));
        m_Colours.AddTail(PALETTERGB(0x80, 0x80, 0x80));
        m_Colours.AddTail(PALETTERGB(0xC0, 0xC0, 0xC0));
        m_Colours.AddTail(PALETTERGB(0xFF, 0x00, 0x00));
        m_Colours.AddTail(PALETTERGB(0x00, 0xFF, 0x00));
        m_Colours.AddTail(PALETTERGB(0x00, 0x00, 0xFF));
        m_Colours.AddTail(PALETTERGB(0xFF, 0x00, 0xFF));
        m_Colours.AddTail(PALETTERGB(0x00, 0xFF, 0xFF));
        m_Colours.AddTail(PALETTERGB(0xFF, 0xC0, 0x00));
        SetDocumentColors(strText, m_Colours);

        // This uses my wrapper as the native method takes literal text
        SetColourName(PALETTERGB(0x00, 0x00, 0x00), IDS_STR_COLOUR_BLACK);
        SetColourName(PALETTERGB(0xFF, 0xFF, 0x00), IDS_STR_COLOUR_YELLOW);
        SetColourName(PALETTERGB(0xFF, 0xFF, 0xFF), IDS_STR_COLOUR_WHITE);
        SetColourName(PALETTERGB(0x80, 0x00, 0x00), IDS_STR_COLOUR_DARK_RED);
        SetColourName(PALETTERGB(0x00, 0x80, 0x00), IDS_STR_COLOUR_DARK_GREEN);
        SetColourName(PALETTERGB(0x80, 0x80, 0x00), IDS_STR_COLOUR_BROWN);
        SetColourName(PALETTERGB(0x00, 0x00, 0x80), IDS_STR_COLOUR_DARK_BLUE);
        SetColourName(PALETTERGB(0x80, 0x00, 0x80), IDS_STR_COLOUR_DARK_PURPLE);
        SetColourName(PALETTERGB(0x00, 0x80, 0x80), IDS_STR_COLOUR_DARK_CYAN);
        SetColourName(PALETTERGB(0x80, 0x80, 0x80), IDS_STR_COLOUR_DARK_GREY);
        SetColourName(PALETTERGB(0xC0, 0xC0, 0xC0), IDS_STR_COLOUR_LIGHT_GREY);
        SetColourName(PALETTERGB(0xFF, 0x00, 0x00), IDS_STR_COLOUR_LIGHT_RED);
        SetColourName(PALETTERGB(0x00, 0xFF, 0x00), IDS_STR_COLOUR_LIGHT_GREEN);
        SetColourName(PALETTERGB(0x00, 0x00, 0xFF), IDS_STR_COLOUR_LIGHT_BLUE);
        SetColourName(PALETTERGB(0xFF, 0x00, 0xFF), IDS_STR_COLOUR_LIGHT_PURPLE);
        SetColourName(PALETTERGB(0x00, 0xFF, 0xFF), IDS_STR_COLOUR_LIGHT_CYAN);
        SetColourName(PALETTERGB(0xFF, 0xC0, 0x00), IDS_STR_COLOUR_ORANGE);

        Now, if you do that with your button, you get a second group of colours that will show the text in the tooltips.

        But if you use the CPalette, on either a button or a grid colour property, whilsts it changes the first group of colours, it still shows all the descriptions in Hex.

        Andrew

  5. Hi,
    I used CMFCPropertyGridCtrl in propety list with edit box( ex: Width 10, height 20 )
    how to select the value(10 ) when click the edit box in property window?

  6. Hi,
    Could you please tell me how to disable the closing button “X” ?
    I need to avoid the user closes the property window
    Thanks

  7. I used CMFCPropertyGridColorProperty control for set colors in property grid control. can i use message box when that color dialog was opened.

    my problem is when open color dialog in property grid control, at a time open message box within the onUpdateValue() function. (Crashed issue )

  8. Hoe to set no color option in Color Property and by default color picker show no color in its value?

  9. […] MFC Feature Pack Tutorial – Part 3 – CMFCPropertyGridCtrl […]

  10. Hi

    Please tell me how to create Dialog box with MFC feature pack without property sheet. Is it possible?

    Feel and look of form is not gud (It is simple just like VB form look)

    Thanks
    Sandeep

  11. Hi

    Please tell me how to create a setup and deployment of mfc feature pack appication to install application on another system.

    Thanks

  12. thanks, but I got a question. I build a project of Office 2007 style with a property window and a output window on the right and the bottom respectively. When I hide both, they never come out again. I am a rookie of MFC, especially the UI part, so could you show me how to get them out again. This kind of sliding windows are really cool.

  13. Thanks for this: helps muchly.

  14. Hey! I’d like to add properties which can be validated, let’s say I want to display a value where the minumum value is 7 and the max is 10.5. How can I do that? Before saving it in the Document.. I want to be able to validate the data… Thank you!

  15. Hi Dan,

    Thanks for your comments!

    Well the screenshot is the result of those two lines on my system at least.

    MFC feature pack has a demo called NewControls, it’s an excellent sample which demostrates these features.

    Tell me if you still have problems!

  16. Really helpful code thanks – got this working in no time.

    I’ve a question about a detail in this code which isn’t really to do with the article – the first two lines don’t seem to do anything, at least not if you’re running XP. I can’t actually find a way to get a dialog box to use the Office 2007 styles at all if you’re running XP. My MDI application works fine with them, but any dialog box I launch from it uses the XP style which looks a bit strange. Any ideas how to get a dialog box to use the Office 2007 styles?

  17. […] MFC Feature Pack Tutorial – Part 3 – CMFCPropertyGridCtrl […]

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.