Microsoft Corporation
September 1996
A common implementation task is creating a list box within a dialog box. The Microsoft® Foundation Class Library (MFC) dialog data exchange (DDX) automates the moving of data between simple dialog box controls (such as edit boxes) and program data structures. However, moving data between more complex dialog box controls (such as a list box) and program data structures requires a little hand coding on your part.
This article describes a technique for initializing a list box from a data structure in Visual C++®.
The technique of filling a list box requires the following four steps:
The rest of this article walks you, step by step, through a simple programming project that illustrates the process outlined in the previous steps.
Note This project assumes knowledge of the Visual C++® project facilities such as the menu and dialog editors, ClassView, ResourceView, AppWizard, and ClassWizard. It also assumes knowledge of C++ and the Microsoft® Foundation Class Library. All of the steps and code required to finish the project are provided. Remember that pressing F1 provides help on the tool that has the current focus.
In this example, you'll use AppWizard to create a multi-document project. After creating the project, you'll add one menu and two dialog boxes. The menu will provide entry points to the dialog boxes. One dialog box accepts strings and one displays them. Strings entered by the user are stored in the context of the currently open document. The flow of data is from the first dialog box's object, to the current document's object, and, finally, to the second dialog box's object.
Note that this project adds steps—adding a menu and an extra dialog box—to the four mentioned earlier. These extra steps are required to provide data for the list box. The four initial steps are meant as a springboard into your own project. If you want hands-on experience before jumping into your own project, perform the steps below.
The following list shows the steps in this example project:
Begin by using AppWizard to create a project to work in.
Next, add a menu called "Names" to the default set of menus.
In this section you will create a dialog box that has a list box into which a user can enter data.
Type | Location | Name |
Static text | Upper-left corner | IDC_STATIC |
Edit box | Below static text | IDC_ENTERNAME |
Next, add a class for the Enter Name dialog box.
Attribute | Value |
Class Name | CEnterNameDlg |
Class Type | Cdialog |
Dialog ID | IDD_ENTERNAME |
Next, add variables to the Enter Name dialog box class.
Attribute | Value |
Member Variable Name | m_csName |
Category | Value |
Variable Type | Cstring |
In this section you will create a second dialog box. This one will retrieve the data a user enters into the other dialog box. First, draw the new dialog box.
Next, add a class for the Retrieve Names dialog box.
Attribute | Value |
Class Name | CRetrieveNamesDlg |
Class Type | Cdialog |
Dialog ID | IDD_RETRIEVENAMES |
To conclude this section, add variables to the Retrieve Names dialog box class.
CRetrieveNamesDlg requires two variables: one for the IDC_RETRIEVELASTNAME control ID and one for the IDC_RETRIEVENAMES control ID.
Attribute | Value |
Member Variable Name | m_csLastNameEntered |
Category | Value |
Variable Type | Cstring |
Attribute | Value |
Member | Variable |
Name | m_csNames |
Category | Value |
Variable Type | CString |
The next task will be to connect the two dialog boxes to the Names menu.
Objects of type CEnterNameDlg are launched when the user clicks Enter Name (Name menu). CEnterNameDlg accepts strings from the user. User-entered strings are stored in a CStringList in the current document.
#include "stdafx.h"
#include "Name List.h"
>#include "EnterNameDlg.h"
#include "Name ListDoc.h"
.
.
.
void CNameListDoc::OnNameEntername()
{
> CEnterNameDlg dlg;
> if (dlg.DoModal() == IDOK)
> // MFC dialog data exchange returns the user's entry
> // into dlg.m_csName. Add dlg.m_csName to the end of
> // the document's CStringList:
> m_csDocumentNameList.AddTail(dlg.m_csName);
}
This code creates a CEnterNameDlg object when the user selects the Enter Name command from the Name menu. When the user clicks the OK button in the Enter Name dialog, the content of the edit box, dlg.m_csName, is added to the tail of a list.
This code also assumes a CStringList named m_csDocumentNameList in class CNameListDoc. The application's flow of data is from CEnterNameDlg to CNameListDoc to CRetrieveNamesDlg.
To add the CStringList to the document view, open CNameListDoc from ClassView and add the code below marked with ">".
class CNameListDoc : public Cdocument
{
protected: // create from serialization only
CNameListDoc();
DECLARE_DYNCREATE(CNameListDoc)
// Attributes
public:
>// Attributes
>protected:
> // Names entered and retrieved from Name menu
> CStringList m_csDocumentNameList;
This code makes use of the MFC CStringList container class to hold multiple user entries. Later, you'll add the appropriate variables to class CRetrieveNamesDlg in order to complete the data flow.
Next, connect the Retrieve Names dialog box to the Names menu.
#include "stdafx.h"
#include "Name List.h"
#include "EnterNameDlg.h"
>#include "RetrieveNamesDlg.h"
#include "Name ListDoc.h".
.
.
.
void CNameListDoc::OnNameRetrievenames()
{
> CRetrieveNamesDlg dlg;
>// At this point, the DoDataExchange call to DDX_Text that is
>// associated with CNameListDoc::OnNamesRetrievenames
>// automatically performs the required UpdateData call to fill
>// the IDC_RETRIEVELASTNAME text box with user-entered data.
> dlg.m_csLastNameEntered = m_csDocumentNameList.GetTail();
>
>// Assign a pointer to the document's CStringList to
>// the dialog box object's CstringList.
> dlg.m_pcsNameList = &m_csDocumentNameList;
> if (dlg.DoModal() == IDOK)
> {
> }
}
This code creates a CRetrieveNamesDlg object when the user clicks Retrieve Name (on the Name menu). The object's data members are initialized to contain the document's data. After the call to DoModal, DDX automatically fills the IDC_RETRIEVELASTNAME text box with user-entered data.
The final two steps in this exercise are to add a CStringList to the CRetrieveNamesDlg class and to add some code to CRetrieveNamesDlg::OnInitDialog, which fills the dialog box's list box from the CstringList.
One important data structure is missing from the CRetrieveNamesDlg class: a CStringList to contain user-entered data. Open CRetrieveNamesDlg from ClassView and add the code below marked with ">".
class CRetrieveNamesDlg : public Cdialog
{
// Construction
public:
CRetrieveNamesDlg(CWnd* pParent = NULL); // standard constructor
// Dialog Data
//{{AFX_DATA(CRetrieveNamesDlg)
enum { IDD = IDD_RETRIEVENAMES };
CString m_csNames;
CString m_csLastNameEntered;
//}}AFX_DATA
>CStringList* m_pcsNameList;
This added CStringList allows you to assign the user-entered data stored in a CNameListDoc object to a CRetrieveNamesDlg object. In the final step you will add code to CRetrieveNamesDlg::OnInitDialog, which fills the dialog box's list box from the CStringList.
BOOL CRetrieveNamesDlg::OnInitDialog()
{
CDialog::OnInitDialog();
> CListBox* pLB = (CListBox*) GetDlgItem(IDC_RETRIEVENAMES);
> POSITION p = m_pcsNameList->GetHeadPosition();
> while(p != NULL )
> {
> pLB->InsertString(-1, m_pcsNameList->GetNext(p));
> }
return TRUE; // Return TRUE unless you set the focus to a control.
// EXCEPTION: OCX Property Pages should return FALSE.
}
This code creates a pointer to a ListBox, associates it with the dialog box's list box, and uses the member functions of a CStringList to fill the list box. The data transfer is complete. Build and run the application.