Creating Dialog Resources and Instantiating Multiple Instances of a Dialog Box


In this code example a project was created in Visual Studio that is a Microsoft Foundation Classes (MFC) application that is dialog based. The class ProjectNamedlg.cpp defines a dialog box that is the main window for the application. Additional dialog boxes are created in the application using dialog resources.

When the application is run a dialog box appears with three buttons on it. Clicking one button will create and show a simple dialog box that displays a text message. Clicking the second button will create and show a simple dialog box that displays a double value. Clicking the third button will create and show a simple dialog box that displays a double value and shows the value in very simple chart. You can click either button as many times as you wish. DO NOT CLICK THE OK BUTTON ON ANY OF THE DIALOGS. To do so will destroy the dialog and leave a dangling pointer in a vector.

Once every second a timer event will be passed to the application which will then iterate through a vector of type 1 dialog boxes and change the message displayed in each, it will then iterate through a vector of type 2 dialog boxes and change the value displayed in each, and finally it will iterate through a vector of type 3 dialog boxes and change the value displayed in each.

To terminate the application click the Exit button on the main dialog box.

Creating the Dialog Based Project

  1. Select File->New->Project and select MFC Application as shown (figure 1).
    Figure 1
  2. In the next dialog box, on the Application Type tab use the settings as shown (figure 2), then click Finish
    Figure 2
  3. Visual Studio will create all of the files as shown in the listing below (figure 3). The file named ProjectNameDlg.cpp is the class implementation file for the main dialog box.
    Figure 3
  4. Look at the Resource View pane for the project. Locate the Dialog resource representing the main dialog box (figure 4).
    Figure 4
  5. Double click the dialog resource to open it in the resource editor. Modify the dialog resource (delete the cancel button, change the OK button to Exit, and add three additional buttons as shown (figure 5).

    Figure 5
    You could at this point compile and run the application to see what it looks like.

Creating the Dialog Resources

  1. Right click the resources folder in the project and select New->Resource (figure 6).

    Figure 6
  2. In the dialog box that pops up (figure 7) select Dialog in the list then click the New button.

    Figure 7
  3. Use the resource editor to modify the new dialog resource so that it looks like the one in figure 8.

    Figure 8
  4. Now create a second dialog resource and use the resource editor to modify it so that it looks like the one in figure 9.

    Figure 9
  5. Now create a third dialog resource and use the resource editor to modify it so that it looks like the one in figure 10.

    Figure 10

Create classes to represent each of the dialog resources

  1. Right click the main frame of a dialog resource in the resource editor view and select add class from the popup menu (figure 10).

    Figure 11
  2. In the dialog box that appears (figure 11) provide a name for the class. In the Dialog ID combobox field you should see the resource ID of the dialog which will be used to create the on-screen dialog box that this class will be associated with. Click Finish and the .h and .cpp files will be created.

    Figure 12
  3. Look at the code listings below to see the code added to each of the .h and .cpp files. The additions are enclosed in comments like this:
    	//------------------------------------------------
    		Code changes appear here...
    	//------------------------------------------------
    

Add code and event listeners to the main dialog class.

  1. Open the main dialog in the resource editor. The easiest way to do this is to locate the resource ID for the dialog in the resource view hierarchy tree and double click it.
  2. Double click each of the "add" buttons to add an event handler to the ProjectNameDlg.cpp file.
  3. Add two vectors to the ProjectNameDlg.h file. See the code listing below. Don't forget to #include <vector>
  4. Add the line afx_msg void OnTimer (UINT TimerVal); as shown in the ProjectNameDlg.h file below. This defines the function that a timer will call each time it is triggered.
  5. In the ProjectNameDlg.cpp file (see below) you will add code in six places:
    See the code listing below for details.

Add code to the three other dialog classes.

  1. In each of the dialog .h files (MultiDialog1.h, MultiDialog2.h, and MultiDialog3.h in this example add the #include <string>. In the first dialog add the display() and setMessage() functions and a string to hold the message to display in the text box. In the second and third dialog add the display(), setData(), and getData() functions and a double to hold the data.
  2. In each of the dialog .cpp files add the function implementations as shown in the code listings below.

Source listing for the MultiDialogDemoDlg.h class header file.
// MultiDialogDemoDlg.h : header file
//

#pragma once

//---------------------------------------------------
#include <vector>
#include "MultiDialog1.h"
#include "MultiDialog2.h"
#include "MultiDialog3.h"
using namespace std;
//---------------------------------------------------

// CMultiDialogDemoDlg dialog
class CMultiDialogDemoDlg : public CDialog
{
// Construction
public:
	CMultiDialogDemoDlg(CWnd* pParent = NULL);	// standard constructor

// Dialog Data
	enum { IDD = IDD_MULTIDIALOGDEMO_DIALOG };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV support


// Implementation
protected:
	HICON m_hIcon;

	// Generated message map functions
	virtual BOOL OnInitDialog();
	afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
	DECLARE_MESSAGE_MAP()
//---------------------------------------------------
// These are the two event handler functions added
//  when the buttons on the dialog were double clicked
//  from the resource editor.
public:
	afx_msg void OnBnClickedButton1();
	afx_msg void OnBnClickedButton2();
	afx_msg void OnBnClickedButton3();
	// You must manually add the next line
	afx_msg  void  OnTimer (UINT TimerVal);  

	// Vectors to hold pointers to each of the types of dialog boxes
private:
	vector<MultiDialog1 *> m_vDialog1;
	vector<MultiDialog2 *> m_vDialog2;
	vector<MultiDialog3 *> m_vDialog3;

	//---------------------------------------------------
};

Source listing for the MultiDialogDemoDlg.cpp class implementation file.
// MultiDialogDemoDlg.cpp : implementation file
//
#define _CRT_SECURE_NO_WARNINGS
#include "stdafx.h"
#include "MultiDialogDemo.h"
#include "MultiDialogDemoDlg.h"
//------------------------------------------------------
#include "MultiDialog1.h"
#include "MultiDialog2.h"
#include "MultiDialog3.h"
#include <math.h>
#include <time.h>
//------------------------------------------------------
#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:
	CAboutDlg();

// Dialog Data
	enum { IDD = IDD_ABOUTBOX };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

// Implementation
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
END_MESSAGE_MAP()


// CMultiDialogDemoDlg dialog




CMultiDialogDemoDlg::CMultiDialogDemoDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CMultiDialogDemoDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CMultiDialogDemoDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CMultiDialogDemoDlg, CDialog)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	//}}AFX_MSG_MAP
	ON_BN_CLICKED(IDC_BUTTON1, &CMultiDialogDemoDlg::OnBnClickedButton1)
	ON_BN_CLICKED(IDC_BUTTON2, &CMultiDialogDemoDlg::OnBnClickedButton2)
	ON_BN_CLICKED(IDC_BUTTON3, &CMultiDialogDemoDlg::OnBnClickedButton3)
//------------------------------------------------------
	// Add a catch for the timer event
	ON_WM_TIMER (&CMultiDialogDemoDlg::OnTimer) 
//------------------------------------------------------

END_MESSAGE_MAP()


// CMultiDialogDemoDlg message handlers


BOOL CMultiDialogDemoDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Add "About..." menu item to system menu.

	// IDM_ABOUTBOX must be in the system command range.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		CString strAboutMenu;
		strAboutMenu.LoadString(IDS_ABOUTBOX);
		if (!strAboutMenu.IsEmpty())
		{
			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

	// TODO: Add extra initialization here
//------------------------------------------------------
	srand((unsigned int)(time(NULL)));   // Seed the random number generator
	// Create a 1 second timer
	CWnd::SetTimer(1, 1000, 0);

//------------------------------------------------------


	return TRUE;  // return TRUE  unless you set the focus to a control
}

void CMultiDialogDemoDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialog::OnSysCommand(nID, lParam);
	}
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CMultiDialogDemoDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

// The system calls this function to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CMultiDialogDemoDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}


void CMultiDialogDemoDlg::OnBnClickedButton1()
{
	// TODO: Add your control notification handler code here
//------------------------------------------------------
	MultiDialog1 *dlg = new MultiDialog1(); // Instantiate the class
	dlg->Create(IDD_DIALOG1, NULL);         // Create the dialog box
	dlg->ShowWindow(SW_SHOWNORMAL);         // Show it
	string s = "Initial message";           // Create start message
	dlg->setMessage(s);					    // Set an initial message value
	dlg->display();
	m_vDialog1.push_back(dlg);              // Add it to the vector
//------------------------------------------------------
}

void CMultiDialogDemoDlg::OnBnClickedButton2()
{
	// TODO: Add your control notification handler code here
//------------------------------------------------------
	MultiDialog2 *dlg = new MultiDialog2(); // Instantiate the class
	dlg->Create(IDD_DIALOG2, NULL);         // Create the dialog box
	dlg->ShowWindow(SW_SHOWNORMAL);         // Show it
	dlg->setData((double)(rand() % 100));   // Set an initial data value
	dlg->display();
	m_vDialog2.push_back(dlg);              // Add it to the vector
//------------------------------------------------------
}
void CMultiDialogDemoDlg::OnBnClickedButton3()
{
//------------------------------------------------------
	// TODO: Add your control notification handler code here
//------------------------------------------------------
	MultiDialog3 *dlg = new MultiDialog3(); // Instantiate the class
	dlg->Create(IDD_DIALOG3, NULL);         // Create the dialog box
	dlg->ShowWindow(SW_SHOWNORMAL);         // Show it
//	dlg->setData((double)(rand() % 100));   // Set an initial data value
//	dlg->display();
	m_vDialog3.push_back(dlg);              // Add it to the vector
	OnPaint();
}

//------------------------------------------------------
void CMultiDialogDemoDlg::OnTimer(UINT nIDEvent)
{
	// Update the data in all of the dialog1 objects
	for(vector<MultiDialog1 *>::iterator it=m_vDialog1.begin();
			it != m_vDialog1.end(); it++)
	{
		// Create a random message
		string msg = "Message - ";
		char str[32];
		int val = rand();
		sprintf(str, "%d", val);
		msg.append(str);
		(*it)->setMessage(msg);
		(*it)->display();
	}

	// Update the data in all of the dialog2 objects
	for(vector<MultiDialog2 *>::iterator it=m_vDialog2.begin();
			it != m_vDialog2.end(); it++)
	{
		// Decrement by 1.0 the data in each dialog2
		// If it drops to 0 or below reset to another random value
		double d = (*it)->getData();
		if(d > 0.0) d-= 1.0;
		if(d <= 0.0) d = (double)(rand() % 100);
		(*it)->setData(d);
		(*it)->display();
	}
	// Update the data in all of the dialog3 objects
	for(vector<MultiDialog3 *>::iterator it=m_vDialog3.begin();
			it != m_vDialog3.end(); it++)
	{
		// Decrement by 1.0 the data in each dialog3
		// If it drops to 0 or below reset to another random value
		double d = (*it)->getData();
		if(d > 0.0) d-= 1.0;
		if(d <= 0.0) d = (double)(rand() % 100);
		(*it)->setData(d);
		(*it)->display();
	}

	CDialog::OnTimer(nIDEvent); // Pass on to super
}
//------------------------------------------------------



Source listing for the MultiDialog1.h class header file.
#pragma once

//--------------------------------------------------------
#include <string>

using namespace std;
//--------------------------------------------------------

// MultiDialog1 dialog

class MultiDialog1 : public CDialog
{
	DECLARE_DYNAMIC(MultiDialog1)

public:
	MultiDialog1(CWnd* pParent = NULL);   // standard constructor
	virtual ~MultiDialog1();
//--------------------------------------------------------
	// Display message function
	void display();

	void setMessage(string msg);
private:
	string m_sMessage;;
//--------------------------------------------------------

// Dialog Data
	enum { IDD = IDD_DIALOG1 };

protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

	DECLARE_MESSAGE_MAP()
};

Source listing for the MultiDialog1.cpp class header file.
// MultiDialog1.cpp : implementation file
//

#include "stdafx.h"
#include "MultiDialogDemo.h"
#include "MultiDialog1.h"


// MultiDialog1 dialog

IMPLEMENT_DYNAMIC(MultiDialog1, CDialog)

MultiDialog1::MultiDialog1(CWnd* pParent /*=NULL*/)
	: CDialog(MultiDialog1::IDD, pParent)
{
//------------------------------------------------------
	m_sMessage = ""; // Initialize the string
//------------------------------------------------------
}

MultiDialog1::~MultiDialog1()
{
}

void MultiDialog1::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
}

//------------------------------------------------------
//-----------------------
// Show the message
//-----------------------
void MultiDialog1::display()
{
	// Get the character array out of the string for the text field text.
	this->GetDlgItem(IDC_EDIT1)->SetWindowTextA(m_sMessage.c_str());
}

//----------------------------
// Set the Message to display
//----------------------------
void MultiDialog1::setMessage(string msg)
{
	this->m_sMessage.assign(msg);
}
//-----------------------------------------------------
BEGIN_MESSAGE_MAP(MultiDialog1, CDialog)
END_MESSAGE_MAP()


// MultiDialog1 message handlers


Source listing for the MultiDialog2.h class implementation file.
#pragma once


// MultiDialog2 dialog
//--------------------------------------------------------
#include <string>

using namespace std;
//--------------------------------------------------------

class MultiDialog2 : public CDialog
{
	DECLARE_DYNAMIC(MultiDialog2)

public:
	MultiDialog2(CWnd* pParent = NULL);   // standard constructor
	virtual ~MultiDialog2();
//--------------------------------------------------------
	// Display data function
	void display();
	void setData(double data);
	double getData();

private:
	double m_dData;
//--------------------------------------------------------

// Dialog Data
	enum { IDD = IDD_DIALOG2 };

protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

	DECLARE_MESSAGE_MAP()
};


Source listing for the MultiDialog2.cpp class implementation file.
// MultiDialog2.cpp : implementation file
//

//-----------------------------------------------------------
#define _CRT_SECURE_NO_WARNINGS // Ignore K&R string warnings
#include "stdafx.h"
#include "MultiDialogDemo.h"
#include "MultiDialog2.h"
//-----------------------------------------------------------

// MultiDialog2 dialog

IMPLEMENT_DYNAMIC(MultiDialog2, CDialog)

MultiDialog2::MultiDialog2(CWnd* pParent /*=NULL*/)
	: CDialog(MultiDialog2::IDD, pParent)
{

}

MultiDialog2::~MultiDialog2()
{
}

void MultiDialog2::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
}

//-----------------------------------------------------------
//--------------
// Show the data
//--------------
void MultiDialog2::display()
{
	char dataStr[32];
	sprintf(dataStr, "%.4f", m_dData); // Make a string
	this->GetDlgItem(IDC_EDIT1)->SetWindowTextA(dataStr);
}

//--------------
// Set the data
//--------------
void MultiDialog2::setData(double data)
{
	this->m_dData = data;
}

//--------------
// Get the data
//--------------
double MultiDialog2::getData()
{
	return m_dData;
}
//-----------------------------------------------------------

BEGIN_MESSAGE_MAP(MultiDialog2, CDialog)
END_MESSAGE_MAP()


// MultiDialog2 message handlers

Source listing for the MultiDialog3.h class header file.
#pragma once
#include "afxwin.h"


// MultiDialog3 dialog

class MultiDialog3 : public CDialog
{
	DECLARE_DYNAMIC(MultiDialog3)

public:
	MultiDialog3(CWnd* pParent = NULL);   // standard constructor
	virtual ~MultiDialog3();
//--------------------------------------------------------
	afx_msg void OnPaint();
	// Display data function
	void display();
	void setData(double data);
	double getData();

private:
	double m_dData;
//--------------------------------------------------------

// Dialog Data
	enum { IDD = IDD_DIALOG3 };

protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

	DECLARE_MESSAGE_MAP()
public:
	CEdit m_DataValueTextbox;
};

Source listing for the MultiDialog3.cpp class header file.
// MultiDialog3.cpp : implementation file
//

#include "stdafx.h"
#include "MultiDialogDemo.h"
#include "MultiDialog3.h"


// MultiDialog3 dialog

IMPLEMENT_DYNAMIC(MultiDialog3, CDialog)

MultiDialog3::MultiDialog3(CWnd* pParent /*=NULL*/)
	: CDialog(MultiDialog3::IDD, pParent)
{

}

MultiDialog3::~MultiDialog3()
{
}

void MultiDialog3::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_EDIT1, m_DataValueTextbox);
}


BEGIN_MESSAGE_MAP(MultiDialog3, CDialog)
END_MESSAGE_MAP()

void MultiDialog3::OnPaint()
{
	CDialog::OnPaint();
	CDC *cdc = this->GetDC();

	cdc->FillSolidRect(10, 30, 250, 50, RGB(255, 255, 255));
	// m_dData value can be 0..100
	// line X position is 2 * m_dData + 10 pixels to get into the solid rect
	cdc->MoveTo(2*((int)(m_dData))+10, 30); // Draw line in the boundaries
	cdc->LineTo(2*((int)(m_dData))+10, 80);
}
//-----------------------------------------------------------
//--------------
// Show the data
//--------------
void MultiDialog3::display()
{
	char dataStr[32];
	sprintf(dataStr, "%.4f", m_dData); // Make a string
	this->GetDlgItem(IDC_EDIT1)->SetWindowTextA(dataStr);
	OnPaint();
}

//--------------
// Set the data
//--------------
void MultiDialog3::setData(double data)
{
	this->m_dData = data;
}

//--------------
// Get the data
//--------------
double MultiDialog3::getData()
{
	return m_dData;
}
//-----------------------------------------------------------

The image below shows what the application looks like when running with one of each dialog box type displayed.


Figure 13


To download a copy of the MultiDialogDemo program do the following:
  1. Click on this Demo link to download a zip file called MultiDialogDemo.
  2. Unzip the archive file to find a single file called MultiDialogDemo.txt. The .exe extension on the end was changed to .txt to avoid problems with some firewalls when downloading zip files containing executables.
  3. Change the .txt extension back to .exe.
  4. Double click the executable to run the program.