New Controls for MFC

Looking for information on the new controls in the MFC Feature Pack? Don't expect to find it in a book. Keep reading this article, on the other hand, and you'll find all the details you could want.

Contributed by
Rating: 3 stars3 stars3 stars3 stars3 stars / 4
October 20, 2009
Rate this Article:
MEH MEH++


SEARCH ASP FREE
TOOLS YOU CAN USE

advertisement

Nowadays, there are a couple of fast evolving markets. IT is certainly one of them. Documenting all the modifications and extending them is hard work. There are countless hours of intensive research, writing, probing and rewriting of entire paragraphs for a technical book to appear. By the time you manage to write a high quality book, there is a high chance that technology you describe it is already outdated.

Therefore, I am not surprised that last time I searched for a book/article describing the new controls introduced by the MFC Feature Pack, I found nothing. This article will try to fill this lack. I will describe each control in depth, in code and images. To demonstrate it visually I will use the following sample you can download from the MSDN: New Controls.

Although I find the online documentation hard to decipher, what is truly interesting is that this application is well written. You can split up the controls into six main categories: Buttons, Color Controls, Masked Edit, List Controls, Shell Controls and other controls. The application will resemble this list.

We will integrate all the controls into a single dialog. To avoid a big mess, we will use property pages. There exists a class for this in the feature pack as well, named CMFCPropertyPage. This supports the display of pop-up menus on a property. This is just what we need. To use them, we need to complete a couple of steps.

First, start up the resource manager and add a new dialog. Populate it with various controls that will host the new ones. Obviously, you will not find the corresponding items in the toolbox to do so. However, use items that behave similarly. For instance, a color picker acts like a button: push it in a place and you generate an action.

Then use the add class option for the dialog. Within this, you can replace the button's definition -- for example, with a color picker, and so on. Replace the CDHtmlDialog to CMFCPropertyPage. Now we can override/extend two main functions.

The application calls the OnInitDialog when it creates the property page. The second call is to the DoDataExchange, which will help us to synchronize the data inside the property page and the ones in the memory. Use the first to initialize the objects and define their behavior. If you created the right type of object, you can leave the second function as it is. It will synchronize any specific change to the corresponding function.

Create a property sheet inside a dialog

You can do the same with all the property pages. Once that is done, we should add all of them inside a CMFCPropertySheet. Derive a class from this. Use the dynamic declaration scheme. Declare as members each of the property pages. Then make the constructor build the sheet as follows:

NewControlsPropSheet::NewControlsPropSheet (CWnd* pParentWnd)

: CMFCPropertySheet (IDS_CAPTION, pParentWnd)

{

BOOL b32BitIcons = afxGlobalData.bIsOSAlphaBlendingSupport;

 

if (afxGlobalData.m_nBitsPerPixel == 16)

{

// 32-bit icons in 16 bpp display mode

// are correctly displayed in WinXP only

 

OSVERSIONINFO osvi;

osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);

::GetVersionEx(&osvi);

 

b32BitIcons = (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT && (osvi.dwMajorVersion > 5 || (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion >= 1)));

}

 

//Set the outlook

SetLook(CMFCPropertySheet::PropSheetLook_OutlookBar);

//Set the icons

SetIconsList(b32BitIcons ? IDB_ICONS32 : IDB_ICONS, 32);

 

//Add the pages one by one

AddPage(&m_Page1);

AddPage(&m_Page2);

AddPage(&m_Page3);

AddPage(&m_Page4);

AddPage(&m_Page5);

AddPage(&m_Page6);

 

//Load the icon what we will set later for the program

m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

}

 

 

In the initialization function we just set the icons for the application, and perhaps add an about menu item to the systems menu. The code snippet for this is self-explanatory:

 

 

// IDM_ABOUTBOX must be in the system command range.

ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);

ASSERT(IDM_ABOUTBOX < 0xF000);

 

// Acquire a pointer to the system menu

 

CMenu* pSysMenu = GetSystemMenu(FALSE);

if (pSysMenu != NULL)

{

 

// set a String to display

CString strAboutMenu;

strAboutMenu.LoadString(IDS_ABOUTBOX);

if (!strAboutMenu.IsEmpty())

{

//Add the separator and the menu item

pSysMenu->AppendMenu(MF_SEPARATOR);

pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);

}

}

 

// Set the icon for this dialog.

// The framework does this automatically

// when the application's main window is not a dialog

SetIcon(m_hIcon, TRUE); // Set big icon

SetIcon(m_hIcon, FALSE); // Set small icon

 

With this, we added the menu item. However, selecting it at this point will not have any effect. For that, we need to catch the command sent by the system and process it. Overwrite the OnSysCommand function and set it for the incoming message.

afx_msg void OnSysCommand (UINT nID, LPARAM lParam);

 

...

BEGIN_MESSAGE_MAP (NewControlsPropSheet, CMFCPropertySheet)

ON_WM_SYSCOMMAND ()

END_MESSAGE_MAP ()

...

 

void NewControlsPropSheet::OnSysCommand (UINT nID,

LPARAM lParam)

{

if ((nID & 0xFFF0) == IDM_ABOUTBOX)

{

// Display a dialog box or what else do you want to do

}

else

{

CMFCPropertySheet::OnSysCommand (nID, lParam);

}

}

This concludes the frame section of our application. Now we can focus on our controls.

Style and Radio Buttons

The new name for a button's class is CMFCButton. This adds functionalities such as text alignment inside the button, combining image and text inside a button, selecting a cursor, or specifying a tool tip. Additionally you can specify modern- looking styles for the button, if you wish.

 

 

// OS supports it or not? -> initialization

if (!CMFCVisualManagerWindows::IsWinXPThemeAvailable())

{

m_bXPButtons = FALSE; // set option -> local variable

m_wndXPButtons.EnableWindow(FALSE);

}

else

{

m_wndBorder.EnableWindow(FALSE);

m_wndBorderLabel.EnableWindow(FALSE);

}

 

 

You can change this option with the help of the following static function: CMFCButton::EnableWindowsTheming. By default, this will try to use the Windows theme. The application calls this function automatically upon initialization. For demonstration purposes, we will put a checkbox inside our property page, and we will link its state change to the following function:

 

 

void CPage1::OnXpButtons()

{

UpdateData(); // Acquire the state of the check box

 

CMFCButton::EnableWindowsTheming(m_bXPButtons);// set

 

m_wndBorder.EnableWindow(!m_bXPButtons);

m_wndBorderLabel.EnableWindow(!m_bXPButtons);

 

RedrawWindow(); // Update the look

}

 

Using the CMFCButton class, we can also create some custom radio buttons. Add a button for each radio button. After you create the class from the file, you need to make sure that you call the DDX_Control function. This is going to subclass the control in the dialog box.

 

void CPage1::DoDataExchange(CDataExchange* pDX)

{

...

DDX_Control(pDX, IDC_RADIO1, m_btnRadio1);

...

}

 

Afterward, set the style of the button to semi-flat. Now we create some images to display as "checks," one for the modern alpha-blend support and one for the older systems. Set an image to the button. This will be on when it is not checked. Then set a checked image. Now we need to resize our controls to fit in.

You can also set the text now, or use the radio button's text from inside the resource view. Finally, set one of the checkboxes as checked. This is all there is to it. You can call the IsChecked() function to find out what is currently on, or just link some event handlers to your check boxes and use an internal variable of your own to follow this.

 

BOOL CPage1::OnInitDialog()

{

...

m_btnRadio1.m_nFlatStyle = CMFCButton::BUTTONSTYLE_SEMIFLAT;

m_btnRadio1.SetImage(afxGlobalData.bIsOSAlphaBlendingSupport ? IDB_RADIO_OFF32 : IDB_RADIO_OFF);

m_btnRadio1.SetCheckedImage(afxGlobalData.bIsOSAlphaBlendingSupport ? IDB_RADIO_ON32 : IDB_RADIO_ON);

m_btnRadio1.SizeToContent();

m_btnRadio1.SetCheck(TRUE);

...

}

Push buttons

However, returning to the push button. As I just presented, you can add an image near the text image. Customize the position of these two so that they're related to each other, or disable some of it.

Add a new button to the resource property page. Modify it to the new extended one: CMFCButton. Make sure to embed the control inside the dialog. During the initialization, you can make the button transparent with the m_bTransparent member:

m_Button.m_bTransparent = TRUE;

 

If you do not use the systems themes, you can set three types of border: flat, semi-flat or a 3D look:

 

m_Button.m_nFlatStyle = CMFCButton::BUTTONSTYLE_3D;

 

If you do not want to display the image, just set a null image pointer to the button:

 

m_Button.SetImage((HBITMAP) NULL);

 

Alternatively, if you want an image, you actually need to set two images: one for when the button is pushed (it is hot), and one for the other times. Just add/create the new bitmaps and use their resource ID.

if (afxGlobalData.bIsOSAlphaBlendingSupport)

{

m_Button.SetImage(IDB_BTN1_32, IDB_BTN1_HOT_32);

}

else

{

m_Button.SetImage(IDB_BTN1, IDB_BTN1_HOT);

}

 

Use the SetWindowText call to set new text, or just set none by passing an empty string:

 

m_Button.SetWindowText(_T(""));

 

You can change the position of the image if you modify the values of the two public members: m_bRightImage (left/right alignment as compared with the text) and m_bTopImage (up-down alignment as compared with the text). These are bool values. For example, in our case, we delineated three scenarios:

 

switch (m_nImageLocation)

{

case 0:

m_Button.m_bRightImage = FALSE;

m_Button.m_bTopImage = FALSE;

break;

 

case 1:

m_Button.m_bRightImage = TRUE;

m_Button.m_bTopImage = FALSE;

break;

 

case 2:

m_Button.m_bRightImage = FALSE;

m_Button.m_bTopImage = TRUE;

break;

}

 

The m_nAlignStyle will accept three enum values: center, left and right. Use this to align the text inside the button.

 

m_btnRadio1.m_nAlignStyle = CMFCButton::ALIGN_CENTER;

 

Whenever you make a change, it is a good idea to resize the control and invalidate it. This will ensure that the application will draw the most up-to-date state.

 

m_Button.SizeToContent();

m_Button.Invalidate();

 

You can set custom cursors. This is the shape of the mouse while it hovers over the corresponding button. You can use the system default, set a hand cursor or use one from a custom cursor file.

 

switch (m_iCursor)

{

case 0:

m_Button.SetMouseCursor(NULL); //system cursor

break;

 

case 1:

m_Button.SetMouseCursorHand(); // Hand cursor

break;

 

case 2:

m_Button.SetMouseCursor(AfxGetApp()-> LoadCursor(IDC_CURSOR)); // custom

break;

}

 

 

You can set some custom tooltips with the SetTooltip method:

m_Button.SetTooltip(m_strToolTip_text);

 

Here it an image made from integrating all of this inside a group that you can modify on the fly:

Menu buttons

You can also customize a button to bring up a menu when pushed. For this you will first need a menu. Use the resource manager to create one. Create a button as well. Now we will modify this to the CMFCMenuButton type. Load the menu and set it for the button.

m_menu.LoadMenu(IDR_MENU1);

m_btnMenu.m_hMenu = m_menu.GetSubMenu(0)->GetSafeHmenu();

m_btnMenu.SizeToContent();

m_btnMenu.m_bOSMenu = FALSE;

The menu can unfold down or to the right. You can change this behavior with the m_bRightArrow member. If you want the button to be pushed down while you make your choice from the menu, set the m_bStayPressed variable to true.

m_btnMenu.m_bRightArrow = TRUE;

m_btnMenu.m_bStayPressed = TRUE;

You may be able to push down the button itself and bring up the menu with the arrow part, or just bring up the menu regardless of where you push the button. If you want to do the former, you need to set the m_bDefaultClick variable to true, and then link a function to the button (this will be called whenever you make a choice) in the message map:

 

void CPage1::OnButtonMenu()

{

CString strItem;

 

switch (m_btnMenu.m_nMenuResult)

{

case ID_ITEM_1:

strItem = _T("Item 1");

break;

 

case ID_ITEM_2:

strItem = _T("Item 2");

break;

 

case ID_ITEM_3:

strItem = _T("Item 3");

break;

 

case ID_ITEM_4:

strItem = _T("Item 4");

break;

 

default:

if (!m_bMenuDefaultClick)

{

return;

}

strItem = _T("Default Menu Button Action");

break;

}

MessageBox(strItem);

}

Now with this knowledge, creating a check button as in the image below should be easy. It is sort of a single radio button:

 

m_btnCheck.SetImage(afxGlobalData.bIsOSAlphaBlendingSupport ? IDB_CHECKNO32 : IDB_CHECKNO);

m_btnCheck.SetCheckedImage(

afxGlobalData.bIsOSAlphaBlendingSupport ? IDB_CHECK32 : IDB_CHECK);

m_btnCheck.SizeToContent();

m_btnCheck.m_nFlatStyle = CMFCButton::BUTTONSTYLE_SEMIFLAT;

 

The multiline text button is in fact just a simple button. Add all the text you want into it and call the SizeToContent function to turn it into a multiline button.

 

This is all for today. Make sure you come back next time if you are interested in context menus, color pickers and other new additions to MFC with the MFC Feature Pack. Add questions and observations here on the blog or join our  DevHardware forums where you can ask our experts. I would like to ask you to rate my article as you think it deserves and until next time, 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 3 - Follow our Sitemap
Most Popular Topics
All ASP.Net Tutorials