List Control and Property Grid with the MFC Feature Pack

Some of the tools and objects around us are good only for their specific purpose. Under any other circumstances these are as useless as a dollar on a deserted island in the middle of nowhere. However, these tools and objects do wonders if you use them for their proper purpose. The list and grid controls are these kinds of classes in the MFC.

Contributed by
Rating: 5 stars5 stars5 stars5 stars5 stars / 6
October 26, 2009
Rate this Article:
MEH MEH++


SEARCH ASP FREE
TOOLS YOU CAN USE

advertisement

Therefore the question pops up: is it worth it the time to learn them? Well as long as you do not use them, not really. Nevertheless, if you intend to put them to work in your code source and you already have strong pre-feature pack knowledge of the MFC, this article will definitely be the one to skim through.

If you missed or are interested in the other MFC feature pack controls, you can find them under my profile. I've already written three other articles treating this subject. I will continue to use the project entitled New Controls present on the MSDN here. Anyone who may want to follow along with my work will need Visual Studio 2008 installed with service pack one.

First, add a classic list control item in the resource editor. Then add a new class to your project via the editor. Inside the code source generated, replace the CListCtrl item with a CMFCListControl. If you populate it with a couple of simple items you will have already a working Excel-like list.

Customize the list control

Nevertheless, in order to make it a little more interesting we will extend our class a little. Derive from the CMFCListCtrl and we will overwrite three classes, as I show in the following lines:

class CMyListCtrl: public CMFCListCtrl

{

virtual COLORREF OnGetCellTextColor (int nRow, int nColum);

virtual COLORREF OnGetCellBkColor (int nRow, int nColum);

virtual HFONT OnGetCellFont (int nRow, int nColum, DWORD dwData = 0);

 

public:

BOOL m_bColor;

BOOL m_bModifyFont;

};

 

There are two major improvements over the old version. First, you can see what column is sorted by the arrow that is automatically drawn above it, according to what we sort. Second, it is possible now to do the data sorting on multiple columns at the same time.

Moreover, you can use font and color changes to better illustrate this. First we overwrite the function responsible for the text color, then for the cell's background color, and finally the one that will change the font used for text. To keep this simple, we will just make the current font bold.

COLORREF CMyListCtrl::OnGetCellTextColor (int nRow, int nColum)

{// do we set the color or we leave for the def implementation

if (! m_bColor)

{

return CMFCListCtrl::OnGetCellTextColor (nRow, nColum);

}

 

return (nRow % 2) == 0? RGB (128, 37, 0):

RGB (0, 0, 0);

}

 

COLORREF CMyListCtrl::OnGetCellBkColor (int nRow, int nColum)

{// if we set the colors return the corresponding colors

if (! m_bColor)

{

return CMFCListCtrl::OnGetCellBkColor (nRow, nColum);

}

// One color for the sorted columns and one for the others

if (m_bMarkSortedColumn && nColum == m_iSortedColumn)

{

return (nRow % 2) == 0? RGB (233, 221, 229):

RGB (176, 218, 234);

}

 

return (nRow % 2) == 0? RGB (253, 241, 249):

RGB (196, 238, 254);

}

 

 

HFONT CMyListCtrl::OnGetCellFont (int nRow, int nColum, DWORD /*dwData* = 0*/)

{// if we are choosing the font return the corresponding handle

if (! m_bModifyFont)

{

return NULL;

}

 

if (nColum == 2 && (nRow >= 4 && nRow <= 8))

{

// just use a bolded font of what we have

return afxGlobalData.fontDefaultGUIBold;

}

 

return NULL;

}

 

 

Of course we also need to make some initializations for the controls before all this can work:

 

//Constructor Initialization

m_wndList.m_bColor = TRUE;

m_wndList.m_bModifyFont = TRUE;

 

// Populate the list with items during the initialization

m_wndList.InsertColumn (0, _T ("#"), LVCFMT_LEFT, 20);

 

int nColumn;

for (nColumn = 1; nColumn < nColumns - 1; nColumn++) {

m_wndList.InsertColumn (nColumn,

CString ((TCHAR) (_T ('A') + nColumn - 1)), LVCFMT_LEFT, 70) ;}

 

for (int i = 0; i < nRows; i++)

{

CString str;

str.Format (_T ("%d"), i);

m_wndList.InsertItem (i, str);

m_wndList.SetItemData (i, i);

 

for (nColumn = 1; nColumn < nColumns - 1; nColumn++)

{

str.Format (_T ("Item (%d, %d)"), nColumn - 1, i);

m_wndList.SetItemText (i, nColumn, str);

}

}

 

//Select the style we use

m_wndList.SendMessage (LVM_SETEXTENDEDLISTVIEWSTYLE,

0, LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);

// Use the new feature

m_wndList.EnableMarkSortedColumn ();

 

Finally, I have also implemented a few check boxes so you can turn these options on and off. During this, we just change a bool variable and call for the enable/disable function. The update of the variable is done automatically due to the data bind. The update date command will synchronize what you see on the screen with what you see inside the memory.

 

void CPage5::OnMarkSortedColumn ()

{

// Enable/Disable the new feature

UpdateData ();

m_wndList.EnableMarkSortedColumn (m_bMarkSortedColumn);

}

 

void CPage5::OnColorRows ()

{ // Enable/Disable enabling the coloring of rows

UpdateData ();

m_wndList.m_bColor = m_bColor;

m_wndList.RedrawWindow ();

}

 

void CPage5::OnModifyFont ()

{ // Enable/Disable enabling the custom font feature

UpdateData ();

m_wndList.m_bModifyFont = m_bModifyFont;

m_wndList.RedrawWindow ();

}

In the table that follows this paragraph you will see a short description of the other functions you may use. With this, implementing the sort for multiple columns should be child's play. I will leave this task to you.

 

Function

For what?

EnableMarkSortedColumn

Use a different background color for the marked column.

EnableMultipleSort

Enables the ability of multiple sorts.

GetHeaderCtrl

Returns a reference to the header control.

IsMultipleSort

Checks to see if multiple sorts are activated.

OnCompareItems

Called by the framework to compare two items. Overwrite this for a custom sort.

OnGetCellBkColor

Tells what color to use for the background of a cell.

OnGetCellFont

Tells what font to use for drawing cell's content.

OnGetCellTextColor

Tells what color to use for the cell's text.

RemoveSortColumn

Removes the sort column form the list of sorted columns.

SetSortColumn

Sets the current sorted column and the sort order.

Sort

Sorts the list control.

Property Grid

 

In order to make a grid control we need to invest a little more time. First we need a place to create all this. A CStatic object will suffice for this task. Use one of these in the resource editor. Once you have created the class, you need to add a CMFCPropertyGridCtrl variable. This will be the proper item. In the initialization, get the position of the static item and create the list there:

CRect rectPropList;

m_wndPropListLocation.GetClientRect(&rectPropList);

m_wndPropListLocation.MapWindowPoints(this, &rectPropList);

 

m_wndPropList.Create(WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_BORDER, rectPropList, this, (UINT)-1);

 

Function

Effect

AddProperty

Add a new property to the grid control.

Accepts CMFCPropertyGridProperty pointers.

AlwaysShowUserToolTip

Set/unset option.

CloseColorPopup

Closes a color selection pop up

Create

Creates a control and attaches it to a property grid control object.

DeleteProperty

Deletes a property from the grid control.

EnableDescriptionArea

Enables/disables description area underneath the list properties.

EnableHeaderCtrl

Enables/disables the header control at the top of the grid control.

EnsureVisible

Assures that a given property is visible inside the grid. To do this, it will scroll and expand.

ExpandAll

Expands or collapses all properties inside the grid control.

FindItemByData

Returns the property assigned to the given DWORD value.

GetBkColor

Returns the current background color of the grid control.

GetBoldFont

Returns the current font in bold.

GetCurSel

Retrieves the currently selected property.

GetCustomColors

Finds out the colors used for specific items of the control grid.

GetDescriptionHeight

Retrieves the height of an area.

GetDescriptionRows

Retrieves the number of rows of the current property grid control.

GetHeaderCtrl

References the internal internal CMFCHeaderCtrl that the framework uses to display the grid.

GetHeaderHeight

Gets the height of the property grid.

GetLeftColumnWidth

Gets column width.

GetListRect

Shows bounding rectangle of the grid control.

GetProperty

Points to the property according to the given index.

GetPropertyColumnWidth

Gives current width of the column that contains the property values.

GetPropertyCount

Tells the number of properties you have in the grid control.

GetRowHeight

Tells the height of a property row.

GetScrollBarCtrl

Points to the scroll bar used for the grid.

GetTextColor

Gives the color of the text in the current property.

HitTest

Retrieves the property in the given client coordinates.

InitHeader

Initializes the CMFCHeaderCtrl. This is used by the grid control to display the control.

IsAlphabeticMode

Tells whether or not the property grid is in alphabetic mode.

IsAlwaysShowUserToolTip

 

IsDescriptionArea

Tells whether the description area displayed.

IsGroupNameFullWidth

Tells whether each group name is displayed across the width of the current property grid.

IsHeaderCtrl

Indicates whether the header control is displayed

IsMarkModifiedProperties

Tells how modified properties are displayed. 

IsShowDragContext

Tells whether, on resize, the framework redraws the name and values of the grid control.

IsVSDotNetLook

Tells whether it uses the  same style as for the VS.Net.

MarkModifiedProperties

Tells how to display the modified properties.

RemoveAll

Clears out the property grid from the controls.

ResetOriginalValues

Restores the original values for all properties.

SetAlphabeticMode

Sets/resets alphabetical mode.

SetBoolLabels

Tells what text to display for Boolean labels.

SetCurSel

Selects the given property in the grid control.

SetCustomColors

Sets custom colors. These are used to draw the grid.

SetDescriptionRows

Sets the number of rows to display for a description.

SetGroupNameFullWidth

Displays full width of a category name for a group of properties in the current property gird control.

SetListDelimiter

Gives a character to use as delimiter in a list of property values.

SetShowDragContext

Redraws the name/value columns of the grid upon resizing.

SetVSDotNetLook

Sets the look of the VS.Net property grid.

UpdateColor

Sets the color values of the current color property.

 

Now for this plethora of functions there are four main properties: a general one (CMFCPropertyGridProperty), one used to select a color value (CMFCPropertyGridColorProperty), one that you can use to select a file (CMFCPropertyGridFileProperty) and one that you can use to select a font (CMFCPropertyGridFontProperty).

Naturally, extending any of these and rebuilding them to suit you needs is also an option. During the initialization part we can call many of these functions to configure our grid control to look as we want it to. Now the MSDN example creates one of each type of the four properties.

However, I will not do the same, as this would go beyond the purpose and size of this article. I will present one for the color and custom item. The other properties follow the same template; you just need to provide different contextual data at the time of creation.

Properties

A property grid contains multiple groups (or just one), and within that, multiple properties (or just one). Before we add any property, we need to create a group. For this, use the CMFCPropertyGridProperty class. Within this you can add items with the AddSubItem function. You can add a property group to the grid control with the AddProperty function.

//create a new item

CMFCPropertyGridColorProperty* pColorProp =

new CMFCPropertyGridColorProperty(

_T("Window Color"),RGB(210, 192, 254), NULL, _T("Specifies the default dialog color"));

 

// A little customization

pColorProp->EnableOtherButton(_T("Other..."));

pColorProp->EnableAutomaticButton(_T("Default"), ::GetSysColor(COLOR_3DFACE));

 

// Add a new group

CMFCPropertyGridProperty* pGroup3 = new CMFCPropertyGridProperty(_T("Misc"));

// Add the new item into this

pGroup3->AddSubItem(pColorProp);

 

// And finally add the end result to the grid control

m_wndPropList.AddProperty(pGroup3);

 

Creating a custom item is not that hard. You need to know which functions to overwrite and derive from one of the properties. We will create one that will have one accept and one cancel button near an edit box:

//Definition of a class

class CTwoButtonsProp : public CMFCPropertyGridProperty

{

public:

CTwoButtonsProp(const CString& strName,

const COleVariant& varValue);

 

protected:

virtual BOOL HasButton() const { return TRUE; }

virtual void AdjustButtonRect();

virtual void OnClickButton(CPoint point);

virtual void OnDrawButton(CDC* pDC, CRect rectButton);

 

CImageList m_images;

};

 

//Constructor

CTwoButtonsProp::CTwoButtonsProp(const CString& strName,

const COleVariant& varValue) : CMFCPropertyGridProperty(strName, varValue)

{

// Load image and create a list from it

CBitmap bmp;

bmp.LoadBitmap(IDB_BUTTONS);

 

m_images.Create(14, 14, ILC_MASK | ILC_COLOR8, 0, 0);

m_images.Add(&bmp, RGB(255, 0, 255));

}

 

// Change the size of the button

void CTwoButtonsProp::AdjustButtonRect()

{

CMFCPropertyGridProperty::AdjustButtonRect();

m_rectButton.left -= m_rectButton.Width();

}

 

//Action to take upon button click

void CTwoButtonsProp::OnClickButton(CPoint point)

{

BOOL bIsLeft = point.x < m_rectButton.CenterPoint().x;

AfxMessageBox(bIsLeft ? _T("Left button clicked") :

_T("Right button clicked"));

}

 

// How to draw the buttons

void CTwoButtonsProp::OnDrawButton(CDC* pDC, CRect rectButton)

{

for (int i = 0; i < 2; i++)

{

CMFCToolBarButton button;

 

CRect rect = rectButton;

 

if (i == 0)

{

rect.right = rect.left + rect.Width() / 2;

}

else

{

rect.left = rect.right - rect.Width() / 2;

}

 

// Acquire some visual studio style

CMFCVisualManager::AFX_BUTTON_STATE state = CMFCVisualManager::ButtonsIsHighlighted;

 

CMFCVisualManager::GetInstance()-> OnFillButtonInterior(pDC, &button, rect, state);

 

m_images.Draw(pDC, i, CPoint(rect.left, rect.top), ILD_NORMAL);

 

CMFCVisualManager::GetInstance()-> OnDrawButtonBorder(pDC, &button, rect, state);

}

}

 

//Finally in the initialization create an instance of this

pGroup5->AddSubItem(new CTwoButtonsProp(_T("2 Buttons"), _T("text")));

 

The result speaks for itself:

And I will show you some of the other properties and styles you can create. For now this will be only in pictures:

 

 

 

 

 

This will be all for this piece on the MFC Feature Pack. I would like to thank you for reading my article. I hope you have learned a lot and you will rate my article as you think it's worth. If you have any questions feel free to put them up here on the blog or over our friendly community at DevHardware. Live With Passion!

blog comments powered by Disqus
.NET ARTICLES

- .Net 4.5 Brings Changes
- Understanding Events in VB.NET
- Objects, Properties, Events and Methods in V...
- Install Visual Web Developer Express 2010
- Microsoft Gadgeteer an Open Source Alternati...
- Best DotNetNuke Modules
- Facebook Image Viewer in Visual Basic
- Murach`s ADO.NET 4 Database Programming with...
- 5 Must Have Visual Studio 2010 Extensions
- Dynamic Web Applications with ASP.NET Mono u...
- PDFSharp: HTML to PDF in ASP.NET 3.5 using V...
- Using the PDFSharp Library in ASP.NET 3.5 wi...
- Sending Email in ASP.NET 3.5 using VB.NET wi...
- ASP.NET 3.5 Role Based Security and User Aut...
- Creating ASP.NET Login Web Pages and Basic C...

ASP Web Hosting ASP.Net Web Hosting Windows Web Hosting
ASP Free Forums 
 RSS  Tutorials RSS
 RSS  Forums RSS
 RSS  All Feeds
Site Map 
Request Media Kit
Write For Us Get Paid 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
Privacy Policy 
Support 


© 2003-2012 by Developer Shed. All rights reserved. DS Cluster 5 - Follow our Sitemap
Most Popular Topics
All ASP.Net Tutorials