Introduction
In this article, I'll demonstrate how to use the Windows Forms 2.0 MenuStrip
and ToolStrip
controls in an
MFC SDI application, using C++/CLI, to get the Office 2003 style menu and
toolbar. I assume that you already know how to use these new Forms controls
introduced in Whidbey, that you are familiar with C++/CLI syntax, and that you
know about the new Windows Forms interop helper classes that have been added to
MFC 8.
Step-by-step guide
This is a step by step guide to adding the Forms controls to an existing
application. For the example, just use a default SDI app that's generated by
VC++ 8. Note that, the same techniques can be more or less used the same way for
an MDI application too - except you need to change the classes used
accordingly.
Step 1 : Remove the MFC toolbar creation code
Comment out or delete the MFC toolbar creation code, and any references to
it. For a default app, the following lines are to be commented out (or
removed).
Step 2 : Destroy the MFC menu
You can do this in PreCreateWindow
, but for this
example, out of personal choice, we'll do this in OnCreate
- very early on. The idea is that you can do the same thing if you want
to swap the MFC menu for the Forms menu, in response to a user action.
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
GetMenu()->DestroyMenu();
SetMenu(NULL);
Step 3 : Add MenuStrip
and ToolStrip
members to the frame window class
We use the CWinFormsControl
which provides
functionality to host a Forms control in MFC.
CWinFormsControl<System::Windows::Forms::MenuStrip> m_MenuStrip;
CWinFormsControl<System::Windows::Forms::ToolStrip> m_ToolStrip;
Step 4 : Create and initialize the MenuStrip
and
ToolStrip
controls
We do this in OnCreate
. The code below shows what I've
done, and there are a few comments explaining what's being done. It's mostly
standard Windows Forms code in there.
using namespace System::Windows::Forms;
m_MenuStrip.CreateManagedControl(WS_VISIBLE|WS_CHILD,
CRect(0,0,0,25),this, 1001);
m_ToolStrip.CreateManagedControl(WS_VISIBLE|WS_CHILD,
CRect(0,25,0,75),this, 1002);
ToolStripMenuItem^ topitem = gcnew ToolStripMenuItem();
ToolStripMenuItem^ item = gcnew ToolStripMenuItem();
topitem->Text = "File";
m_MenuStrip->Items->Add(topitem);
item->Text = "Open";
item->Image = System::Drawing::Bitmap::FromHicon((System::IntPtr)
LoadImage(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDI_OPEN),
IMAGE_ICON,0,0,LR_DEFAULTCOLOR));
item->Click += MAKE_DELEGATE(System::EventHandler,File_Open_Click);
topitem->DropDownItems->Add(item);
item = gcnew ToolStripMenuItem();
item->Text = "Exit";
item->Image = System::Drawing::Bitmap::FromHicon((System::IntPtr)
LoadImage(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDI_EXIT),
IMAGE_ICON,0,0,LR_DEFAULTCOLOR));
item->Click += MAKE_DELEGATE(System::EventHandler,File_Exit_Click);
topitem->DropDownItems->Add(item);
topitem = gcnew ToolStripMenuItem();
topitem->Text = "Help";
m_MenuStrip->Items->Add(topitem);
item = gcnew ToolStripMenuItem();
item->Text = "About";
item->Image = System::Drawing::Bitmap::FromHicon((System::IntPtr)
LoadImage(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDI_HELP),
IMAGE_ICON,0,0,LR_DEFAULTCOLOR));
item->Click += MAKE_DELEGATE(System::EventHandler,Help_About_Click);
topitem->DropDownItems->Add(item);
ToolStripButton^ tbutton;
tbutton = gcnew ToolStripButton();
tbutton->Size = System::Drawing::Size(50,50);
tbutton->Text = "Open";
tbutton->TextAlign = System::Drawing::ContentAlignment::BottomCenter;
tbutton->ToolTipText = tbutton->Text;
tbutton->Image = System::Drawing::Bitmap::FromHicon((System::IntPtr)
LoadImage(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDI_OPEN),
IMAGE_ICON,0,0,LR_DEFAULTCOLOR));
tbutton->ImageScaling = ToolStripItemImageScaling::None;
tbutton->ImageTransparentColor =
System::Drawing::Color::FromArgb(220,220,220);
tbutton->ImageAlign = System::Drawing::ContentAlignment::TopCenter;
tbutton->TextImageRelation = TextImageRelation::ImageAboveText;
tbutton->Click += MAKE_DELEGATE(System::EventHandler,File_Open_Click);
tbutton->Padding = Padding(5,0,5,0);
m_ToolStrip->Items->Add(tbutton);
tbutton = gcnew ToolStripButton();
tbutton->Size = System::Drawing::Size(50,50);
tbutton->Text = "About";
tbutton->TextAlign = System::Drawing::ContentAlignment::BottomCenter;
tbutton->ToolTipText = tbutton->Text;
tbutton->Image = System::Drawing::Bitmap::FromHicon((System::IntPtr)
LoadImage(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDI_HELP),
IMAGE_ICON,0,0,LR_DEFAULTCOLOR));
tbutton->ImageScaling = ToolStripItemImageScaling::None;
tbutton->ImageTransparentColor =
System::Drawing::Color::FromArgb(220,220,220);
tbutton->ImageAlign = System::Drawing::ContentAlignment::TopCenter;
tbutton->TextImageRelation = TextImageRelation::ImageAboveText;
tbutton->Click += MAKE_DELEGATE(System::EventHandler,Help_About_Click);
tbutton->Padding = Padding(5,0,5,0);
m_ToolStrip->Items->Add(tbutton);
tbutton = gcnew ToolStripButton();
tbutton->Size = System::Drawing::Size(50,50);
tbutton->Text = "Exit";
tbutton->TextAlign = System::Drawing::ContentAlignment::BottomCenter;
tbutton->ToolTipText = tbutton->Text;
tbutton->Image = System::Drawing::Bitmap::FromHicon((System::IntPtr)
LoadImage(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDI_EXIT),
IMAGE_ICON,0,0,LR_DEFAULTCOLOR));
tbutton->ImageScaling = ToolStripItemImageScaling::None;
tbutton->ImageTransparentColor =
System::Drawing::Color::FromArgb(220,220,220);
tbutton->ImageAlign = System::Drawing::ContentAlignment::TopCenter;
tbutton->TextImageRelation = TextImageRelation::ImageAboveText;
tbutton->Click += MAKE_DELEGATE(System::EventHandler,File_Exit_Click);
tbutton->Padding = Padding(5,0,5,0);
m_ToolStrip->Items->Add(tbutton);
Step 5 : Handle OnSize
in your frame window
We need to prevent the view window from showing itself on top of the menu
strip and the tool strip controls we have added. This is done on OnSize
.
void CMainFrame::OnSize(UINT nType, int cx, int cy)
{
CFrameWnd::OnSize(nType, cx, cy);
if(m_MenuStrip.GetSafeHwnd())
{
CRect rect;
RepositionBars(AFX_IDW_CONTROLBAR_FIRST,
AFX_IDW_CONTROLBAR_LAST,0,CWnd::reposQuery,&rect);
m_MenuStrip->Size = System::Drawing::Size(
rect.Width(),m_MenuStrip->Size.Height);
m_ToolStrip->Size = System::Drawing::Size(
rect.Width(),m_ToolStrip->Size.Height);
rect.top += (m_MenuStrip->Size.Height +
m_ToolStrip->Size.Height);
CView* pView = GetActiveView();
if(pView)
{
pView->MoveWindow(rect);
}
}
}
Step 6 : Add delegate maps
These have to be added to the public section in your class declaration. They
essentially map event handlers to class methods.
BEGIN_DELEGATE_MAP( CMainFrame )
EVENT_DELEGATE_ENTRY( File_Exit_Click,
System::Object^, System::EventArgs^)
EVENT_DELEGATE_ENTRY( Help_About_Click,
System::Object^, System::EventArgs^)
EVENT_DELEGATE_ENTRY( File_Open_Click,
System::Object^, System::EventArgs^)
END_DELEGATE_MAP()
Step 7 : Add event handlers
Just write the event handlers that are called when a tool strip button or a
menu is clicked.
void CMainFrame::File_Exit_Click(System::Object^ sender,
System::EventArgs^ e)
{
PostMessage(WM_CLOSE);
}
void CMainFrame::File_Open_Click(System::Object^ sender,
System::EventArgs^ e)
{
PostMessage(WM_COMMAND,ID_FILE_OPEN);
}
void CMainFrame::Help_About_Click(System::Object^ sender,
System::EventArgs^ e)
{
ReleaseCapture();
CAboutDlg aboutDlg;
aboutDlg.DoModal();
}
History
- Feb 21 2006 - Fixed an issue with showing modal dialogs from a
toolbar item click handler.
- Feb 15 2006 - Article first published.