FunctionX - Practical Learning Logo

An Overview of List Boxes

 

An overview of list boxes

Introduction

To get an overview of list boxes, in this exercise, we will simulate the Table Wizard of Microsoft Access.

Preparing the Application

  1. Start Microsoft Visual C++
  2. On the main menu, click File -> New...
  3. On the New dialog box, click the Projects property sheet and click MFC AppWizard (exe)
  4. In the Project Name box, type TableWizard and click OK
  5. On the MFC AppWizard Step 1, click the Dialog Based radio button and click Next
  6. On the second page, change the Title of the dialog to Table Wizard and click Next.
  7. On the third page, click the No Thank You radio button to decline for comments
  8. Click Next, click Finish, and click OK
  9. On the Toolbox, click the Group Box control and click on the Top left section of the dialog
  10. Change its Caption to Categories
  11. On the Toolbox, click the Radio Button control and click in the group box on the dialog box
  12. Change its ID to IDC_RDO_BUSINESS and its Caption to &Business
  13. Add another radio button in the same group
  14. Change its ID to IDC_RDO_PERSONAL ant its Caption to &Personal
  15. Check the Group property of each radio button
  16. On the Toolbox, click the Static Text and click on the dialog under the group box
  17. Change its Caption to Sample Tables
  18. On the Toolbox, click the List Box and click on the dialog under the group box.
  19. Change its ID to IDC_SAMPLE_TABLES and remove the check box on the Sort property
     
    Table Wizard: Setup
     
  20. Right-click anywhere on the dialog and click ClassWizard
  21. Click the Member Variables property sheet.
  22. Double-click IDC_SAMPLETABLES to associate a member with the control.
  23. Type m_SampleTables and set the Category as Control
     
    Add Member Variable
  24. In the same way, associate a member variable for IDC_RDO_BUSINESS. Name it m_SelectBusiness and set its Category to Control, which would make it a CButton type
  25. Also associate a member variable for IDC_RDO_PERSONAL. Name it m_SelectPersonal and make it a Control Category
  26. Click OK on the ClassWizard dialog box.
  27. On the dialog, remove the check mark of the Group property for the Personal radio button
  28. In the Workspace, click the ClassView property sheet and expand the TableWizard Classes folder
  29. Also expand the CTableWizardDlg folder.
  30. Double-click CTableWizardDlg to access its header file.
  31. On top of the file, declare two constant CString variables as follows:
     
    // TableWizardDlg.h : header file
    //
    
    
    #if _MSC_VER > 1000
    #pragma once
    #endif // _MSC_VER > 1000
    
    //////////////////////////////////////////////////////////////////////////
    // CTableWizardDlg dialog
    
    const CString Business[] = { "Contacts",
    			"Customers",
    			"Employees",
    			"Products",
    			"Orders",
    			"Suppliers",
    			"Payments",
    			"Invoices",
    			"Projects",
    			"Events",
    			"Transactions",
    			"Notes" };
    
    const CString Personal[] = { "Addresses",
    			"Video Collection",
    			"Authors",
    			"Books",
    			"Categories",
    			"Music Collection",
    			"Investments",
    			"Notes" };
  32. At the end of the class, declare two private integer variables as follows:
     
                 //}}AFX_MSG
    	DECLARE_MESSAGE_MAP()
    
    private:
    	// Variables used to hold the number of items in their respective array
    	int SizeBusiness;
    	int SizePersonal;
    };
    
    //{{AFX_INSERT_LOCATION}}
  33. Double-click the OnInitDialog() function to access it.
  34. Change it as follows:
     
    BOOL CTableWizardDlg::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);
    		}
    	}
    
    	SetIcon(m_hIcon, TRUE);			// Set big icon
    	SetIcon(m_hIcon, FALSE);		// Set small icon
    	
    	// TODO: Add extra initialization here
    	// Select the Business radio button
    	m_SelectBusiness.SetCheck(1);
    
    	// Get the number of items in the array
    	SizeBusiness	= sizeof(Business) / sizeof(CString);
    	SizePersonal	= sizeof(Personal) / sizeof(CString);
    
    	// Fill out the Sample Tables list with the Business items
    	for(int i = 0; i < SizeBusiness; i++)
    			m_SampleTables.AddString(Business[i]);
    
    	// Select the first item in the Sample Tables list box
    	m_SampleTables.SetCurSel(0);
    
    	return TRUE;  // return TRUE  unless you set the focus to a control
    }
  35. Press Ctrl + F5 to test your program
  36. After testing the program, close it.
  37. In MS Visual C++, press Ctrl + W to access the ClassWizard.
  38. In the ClassWizard, click the Message Maps property sheet and make sure the CTableWizardDlg is selected in the Class Name combo box.
  39. Click the Message Maps property sheet.
  40. In the Class Name combo box, make sure that CTableWizardDlg is selected. Otherwise, select it.
    In the Object IDs list box, click IDC_RDO_BUSINESS
  41. In the Messages list box, double-click BN_CLICKED
  42. Change the name of the function to OnSelectBusiness and click OK
  43. In the Object IDs list, click IDC_RDO_PERSONAL
  44. In the Messages list, double-click BN_CLICKED
  45. Change the name of the function to OnSelectPersonal and click OK.
  46. Click Edit Code and implement both functions as follows:
     
    void CTableWizardDlg::OnSelectBusiness() 
    {
    	// Empty the list
    	m_SampleTables.ResetContent();
    
    	// Fill out the list with Business items
    	for(int i = 0; i < SizeBusiness; i++)
    		m_SampleTables.AddString(Business[i]);
    	m_SampleTables.SetCurSel(0);
    }
    
    void CTableWizardDlg::OnSelectPersonal() 
    {
    	// Empty the lists
    	m_SampleTables.ResetContent();
    
    	// Fill out the list
    	for(int i = 0; i < SizePersonal; i++)
    			m_SampleTables.AddString(Personal[i]);
    	m_SampleTables.SetCurSel(0);
    }
  47. Press Ctrl + W to test your program
  48. Click the radio buttons and make sure that the content of the Sample Tables list changes according to the radio button selected
  49. After testing the dialog box, close it
 

List Boxes Data Exchange

Now we will take care of exchanging data between different list boxes.
  1. Add a new label on the right side of the group box with a caption of Sample Fields
  2. Add a new list box under the Sample Fields label. Set its ID to IDC_SAMPLEFIELDS and remove the check box on its Sort property
     
    Table Wizard: Adding a new list box
  3. Right-click the new list box and click ClassWizard.
  4. Click the Member Variables property sheet. Double-click IDC_SAMPLEFIELDS
  5. Set the variable name to m_SampleFields and the Category to control to make it a CListBox type.
  6. Click OK.
  7. In the header file of CTableWizardDlg class, declare additional CString arrays as follows:
     
    /////////////////////////////////////////////////////////////////////////////
    // CTableWizardDlg dialog
    
    const CString Business[] = { "Contacts",
    			 "Customers",
    			 "Employees",
    			 "Products",
    			 "Orders",
    			 "Suppliers",
    			 "Payments",
    			 "Invoices",
    			 "Projects",
    			 "Events",
    			 "Transactions",
    			 "Notes" };
    
    const CString Personal[] = { "Addresses",
    			 "Video Collection",
    			 "Authors",
    			 "Books",
    			 "Categories",
    			 "Music Collection",
    			 "Investments",
    			 "Notes" };
    
    const CString Contacts[] = { "MailingListID",
    			 "SocialTitle",
    			 "FirstName",
    			 "MiddleName",
    			 "LastName",
    			 "Suffix",
    			"Nickname",
    			 "HomeAddress",
    			 "City",
    			 "StateOrProvince",
    			 "PostalCode",
    			 "CountryOrRegion",
    			 "HomePhone",
    			 "WorkPhone",
    			 "Extension",
    			 "MobileNumber",
    			 "EmergencyName",
    			 "EmergencyPhone",
    			 "Notes" };
    
    const CString Customers[] = { "CustomerID",
    			   "CompanyName",
    			   "CompanyAddress",
    			   "CompanyCity",
    			   "CompanyState",
    			   "companyZIPCode",
    			   "CompanyCountry",
    			   "CompanyPhone",
    			   "BillingAddress",
    			   "FaxNumber",
    			   "WebSite",
    			   "ContactPhone",
    			   "ContactEMail" };
    
    const CString Employees[] = { "EmployeeID",
    			   "EmployeeNumber",
    			   "DateHired",
    			   "Title",
    			   "FirstName",
    			   "MI",
    			   "LastName",
    			   "Address",
    			   "City",
    			   "State",
    			   "ZIPCode",
    			   "Country",
    			   "HomePhone",
    		                "WorkPhone",
    			   "Extension",
    			   "CellPhone",
    			   "EmergencyName",
    			   "EmergencyPhone",
    			   "Comments" };
    
    const CString Addresses[] = { "AddressID",
      			   "FirstName",
    			   "LastName",
    			   "MaritalStatus",
    			   "Address",
    			   "City",
    			   "StateOrProvince",
    			   "PostalCode",
    			   "CountryOrRegion",
    			   "EmergencyName",
    			   "EmergencyPhone",
    			   "Notes" };
    
    const CString VideoCollection[] = { "VideoID",
    			         "VideoTitle",
    			         "CategoryID",
    			         "Director",
    			         "Rating",
    			         "Length",
    			         "VideoReview" };
    			         
    const CString Categories[] = { "CategoryID",
    			   "Category",
    			    "Description" };
    
    const CString Authors[] = { "AuthorID",
    		            "FullName",
    		            "Nationality",
    			"BirthDate",
    			"BirthPlace",
    			"AliveDead",
    			"Comments" };
    
    const CString Books[] = { "BookID",
    		          "BookTitle",
    		          "Author",
    		          "CategoryID",
    		          "Publisher",
    		          "YearPublished",
    		          "NumberOfPages",
    		          "ISBNNumber",
    		          "BookReview" };
  8. In the private section of the class, add new integer variables to hold the dimensions of the arrays as follows:
     
    private:
    	// Variables used to hold the number of items in their respective array
    	int SizeBusiness;
    	int SizePersonal;
    	int SizeContacts;
    	int SizeEmployees;
    	int SizeAddresses;
    	int SizeCustomers;
    	int SizeVideoCollection;
    	int SizeCategories;
    	int SizeAuthors;
    	int SizeBooks;
    };
  9. Access the TableWizardDlg.cpp file
  10. To make sure that the Sample Fields list is initially filled up with the right fields, change the OnInitDialog() function as follows:
     
    BOOL CTableWizardDlg::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);
    		}
    	}
    
    	SetIcon(m_hIcon, TRUE);			// Set big icon
    	SetIcon(m_hIcon, FALSE);		// Set small icon
    	
    	// TODO: Add extra initialization here
    	// Select the Business radio button
    	m_SelectBusiness.SetCheck(1);
    
    	// Get the number of items in the array
    	SizeBusiness	= sizeof(Business) / sizeof(CString);
    	SizePersonal	= sizeof(Personal) / sizeof(CString);
    	SizeContacts	= sizeof(Contacts) / sizeof(CString);
    	SizeAddresses	= sizeof(Addresses) / sizeof(CString);
    	SizeEmployees	= sizeof(Business) / sizeof(CString);
    	SizeCustomers	= sizeof(Business) / sizeof(CString);
    	SizeVideoCollection = sizeof(VideoCollection) / sizeof(CString);
    	SizeCategories  = sizeof(Categories) / sizeof(CString);
    	SizeAuthors		= sizeof(Authors) / sizeof(CString);
    	SizeBooks		= sizeof(Books) / sizeof(CString);
    
    	// Fill out the Sample Tables list with the Business items
    	for(int i = 0; i < SizeBusiness; i++)
    			m_SampleTables.AddString(Business[i]);
    
    	// Select the first item in the Sample Tables list box
    	m_SampleTables.SetCurSel(0);
    
    	// Fill out the Sample Fields list box
    	for(int j = 0; j < SizeContacts; j++)
    		m_SampleFields.AddString(Contacts[j]);
    
    	// Select the first item in the Sample Fields list box
    	m_SampleFields.SetCurSel(0);
    
    	return TRUE;  // return TRUE  unless you set the focus to a control
    }
  11. You can test the program now if you want. Then close the Table Wizard dialog box.
    To make sure that the Sample Fields list is updated when one of the radio buttons is selected, change the OnSelectBusiness() and the OnSelectPersonal() functions as follows:
     
    void CTableWizardDlg::OnSelectBusiness() 
    {
    	// Empty the lists
    	m_SampleTables.ResetContent();
    	m_SampleFields.ResetContent();
    
    	// Fill out the list with Business items
    	for(int i = 0; i < SizeBusiness; i++)
    		m_SampleTables.AddString(Business[i]);
    	m_SampleTables.SetCurSel(0);
    
    	// Fill out the Sample Fields list and select the first item
    	for(int j = 0; j < SizeContacts; j++)
    		m_SampleFields.AddString(Contacts[j]);
    	m_SampleFields.SetCurSel(0);
    }
    
    void CTableWizardDlg::OnSelectPersonal() 
    {
    	// Empty the lists
    	m_SampleTables.ResetContent();
    	m_SampleFields.ResetContent();
    
    	// Fill out the list
    	for(int i = 0; i < SizePersonal; i++)
    			m_SampleTables.AddString(Personal[i]);
    	m_SampleTables.SetCurSel(0);
    
    	// Fill out the Sample Fields list and select the first item
    	for(int j = 0; j < SizeAddresses; j++)
    		m_SampleFields.AddString(Addresses[j]);
    	m_SampleFields.SetCurSel(0);
    }
  12. Test your program and return to MSVC
  13. When the user clicks a table in the Sample Tables list box, we must change the content of the Sample Fields list box and fill it out with the fields that are part of the selected table.
    Press Ctrl + W to access the ClassWizard
  14. Click the Message Maps property sheet. In the Object IDs list, click IDC_SAMPLE_TABLES
  15. In the Messages list, double-click LBN_SELCHANGE
  16. Change the name of the function to OnSelectSampleTables and click OK
  17. Click Edit Code and implement the function as follows:
     
    void CTableWizardDlg::OnSelectSampleTables() 
    {
    	// Before filling out the Sample Fields list box, empty it first
    	m_SampleFields.ResetContent();
    
    	// This string variable will identify the selected table
    	CString ItemSelected;
    	
    	// Get the name of the item selected in the Sample Tables list box
    	// and store it in the CString variable declared above
    	m_SampleTables.GetText(m_SampleTables.GetCurSel(), ItemSelected);
    	
    	// Fill out the Sample Fields list box according to the selected table
    	if( ItemSelected == "Contacts" )
    	{
    		for(int i = 0; i < SizeContacts; i++)
    			m_SampleFields.AddString(Contacts[i]);
    	}
    	else if( ItemSelected == "Customers" )
    	{
    		for(int i = 0; i < SizeCustomers; i++)
    			m_SampleFields.AddString(Customers[i]);
    	}
    	else if( ItemSelected == "Employees" )
    	{
    		for(int i = 0; i < SizeEmployees; i++)
    			m_SampleFields.AddString(Employees[i]);
    	}
    	else if( ItemSelected == "Addresses" )
    	{
    		for(int i = 0; i < SizeAddresses; i++)
    			m_SampleFields.AddString(Addresses[i]);
    	}
    	else if( ItemSelected == "VideoCollection" )
    	{
    		for(int i = 0; i < SizeVideoCollection; i++)
    			m_SampleFields.AddString(VideoCollection[i]);
    	}
    	else if( ItemSelected == "Categories" )
    	{
    		for(int i = 0; i < SizeCategories; i++)
    			m_SampleFields.AddString(Categories[i]);
    	}
    	else if( ItemSelected == "Authors" )
    	{
    		for(int i = 0; i < SizeAuthors; i++)
    			m_SampleFields.AddString(Authors[i]);
    	}
    	else if( ItemSelected == "Books" )
    	{
    		for(int i = 0; i < SizeBooks; i++)
    			m_SampleFields.AddString(Books[i]);
    	}
    	else // If we didn't create a list for the selected table, show nothing
    		m_SampleFields.ResetContent();
    
    	// Select the first item, if any, in the Sample Fields list box
    	m_SampleFields.SetCurSel(0);		
    }
  18. Test your program. Click different radio buttons and click different tables in the Sample Tables list
  19. Return to MSVC
    Here is the dialog we are going to design:
     
    Table Wizard: Adding new buttons
  20. Add a new label to the top right section of the dialog and set its caption to Selected Fields
  21. Add a new list box under the Selected Fields label.
  22. Change its ID to IDC_SELECTEDFIELDS and remove the check mark of its Sort property.
  23. Right-click the new list box and click ClassWizard
  24. Click the Member Variables property sheet and double-click IDC_SELECTEDFIELDS
  25. Change the variable name to m_SelectedFields and make it a Control (CListBox type)
  26. Add a Button between the right list boxes. Set its ID to IDC_BTN_SELECTONE and its Caption to >
  27. Add a new button under the previous one. Set its ID to IDC_BTN_SELECTALL and its Caption to >>
  28. Add a new button under the previous one. Set its ID to IDC_BTN_REMOVEONE and its Caption to <
  29. Add a new button under the previous one. Set its ID to IDC_BTN_REMOVEALL and its Caption to <<
  30. Press Ctrl + W to call the ClassWizard dialog.
  31. Click the Member Variables property sheet.
    Double each of the newly added buttons and create a variable for each as follows:
     
    MFC ClassWizard
  32. Click the Message Maps property sheet.
  33. In the Object IDs list, Click IDC_BTN_SELECTONE.
  34. In the Messages list box, double-click BN_CLICKED
  35. Change the name of the function to OnSelectOne and click OK.
  36. Click Edit Code/
  37. First of all, when the dialog box opens, the Selected Fields list is empty, which means the Remove buttons are not useful. Therefore, we should disable them. To do this, make the following change in the OnInitDialog() function:
     
                 // Since the Selected Field list box is empty, disable the Remove buttons
    	m_RemoveOne.EnableWindow(FALSE);
    	m_RemoveAll.EnableWindow(FALSE);
    
    	return TRUE;  // return TRUE  unless you set the focus to a control
    }
  38. You can test your program if you want and return to MSVC.
    To be able to select an item from the Sample Fields list and transfer it to the Selected Fields list box, implement the function as follows:
     
    void CTableWizardDlg::OnSelectOne() 
    {
    	// Variable that identifies what item is selected in the sample fields
    	CString SourceSelected;
    
    	// Find out what item is selected
    	// Store it in the above variable
    	m_SampleFields.GetText(m_SampleFields.GetCurSel(), SourceSelected);
    
    	// Add the item to the Selected Fields list box
    	m_SelectedFields.AddString(SourceSelected);
    }
  39. Test your program. Select different items in the Sample Fields list and click the > button
  40. Return to MSVC.
  41. First of all, to enhance our application, we need to make sure that the user can double-click an item in the Sample Fields list box and obtain the same behavior as if the > button had been clicked.
    Therefore, press Ctrl + W
  42. In the Message Maps of the ClassWizard, in the Object IDs list, click IDC_SAMPLEFIELDS
  43. In the Messages list, double-click LBN_DBLCLK
  44. Change the name of the function to OnDblClkSampleFields and click OK.
  45. Click Edit Code and implement the function as follows:
     
    void CTableWizardDlg::OnDblClkSampleFields() 
    {
    	// When the user double-clicks an item in the Sample Fields list
    	// behave as if the Select One button was clicked
    	OnSelectOne();	
    }
  46. One of the problems we have at this time is that the user can select the same item more than once, which is not practical for a database's table. Therefore, when the user selects an item, we first need to check whether the Selected Fields list box already contains the item. If it does, we will not allow adding the item. In Microsoft Access, if the item already exists, its name is incremented by 1 and added to the right list. For this exercise, I decided not to implement that behavior, you can do it as an exercise. I will provide an alternate solution shortly.
    Also, once at least one item has been added to the Selected Fields list, we can enable the Remove buttons.
    Change the content of the OnSelectOne() function as follows:
     
    void CTableWizardDlg::OnSelectOne() 
    {
    	// Variable that identifies what item is selected in the sample fields
    	CString SourceSelected;
    
    	// Find out what item is selected
    	// Store it in the above variable
    	m_SampleFields.GetText(m_SampleFields.GetCurSel(), SourceSelected);
    	
    	// Find out if the Selected Fields list is empty
    	if( m_SelectedFields.GetCount() == 0 )
    	{
    		// Since the list is empty, add the selected item
    		m_SelectedFields.AddString(SourceSelected);
    		// Select the newly added item
    		m_SelectedFields.SetCurSel(0);
    	}
    	else // Since the list is not empty
    	{
    		// Look for the selected item in the Selected Fields list
    		int Found = m_SelectedFields.FindString(0, SourceSelected);
    
    		// If the item is not yet in the Selected Fields list, prepare to add it
    		if( Found == -1 )
    		{
    			// Because there is always an item selected in any of our list,
    			// get the index of the currently selected item
    			int CurrentlySelected = m_SelectedFields.GetCurSel();
    
    			// Add the new item under the selected one
    			m_SelectedFields.InsertString(CurrentlySelected + 1, SourceSelected);
    
    			// Select the newly added item
    			m_SelectedFields.SetCurSel(CurrentlySelected + 1);
    		}
    	}
    
    	// Since an item has been selected, enable the Remove buttons
    	m_RemoveOne.EnableWindow();
    	m_RemoveAll.EnableWindow();
    }
  47. Test your program. Double-click various items in the Sample Fields list box and observe the behavior.
  48. Return to MSVC.
  49. Now, we need to deal with the Select All button. What we need to do is to select all items in the Sample Fields list and copy them to the Selected Fields list. As previously, we need to avoid duplicating the names of fields in the same table. Therefore, to add the items to the list, first select one at a time, look for it in the Selected Fields list. If it doesn't exist, then add it. If it already exists, ignore it and consider the next item. This behavior can be performed in a for loop that is used to navigate the items in an array.
    Press Ctrl + W.
  50. In the Object IDs list, click IDC_BTN_SELECTALL
  51. In the Messages list, double-click BN_CLICKED
  52. Change the name of the function to OnSelectAll and click OK
  53. Click Edit Code and implement the function as follows:
     
    void CTableWizardDlg::OnSelectAll() 
    {
    	// This string will represent an item in the Sample Fields list
    	CString Item;
    
    	// This "for" loop will be used to navigate the Sample Fields list
    	for(int i = 0; i < m_SampleFields.GetCount(); i++)
    	{
    		// Consider an item in the Sample Fields list
    		// Store it in the above declared Item variable
    		m_SampleFields.GetText(i, Item);
    
    		// Look for the item in the Selected Fields list
    	// Make sure you start at the beginning of the list, which is item 0
    		int Found = m_SelectedFields.FindString(0, Item);
    
    // If the item is not yet in the Selected Fields list, prepare to add it
    		if( Found == -1 )
    		{
    		// Add the new item at the end of the Selected Fields list
    			m_SelectedFields.AddString(Item);
    
    			// Select the last item of the Selected Fields list
    		m_SelectedFields.SetCurSel(m_SelectedFields.GetCount() - 1);
    		} // Consider the next item
    	}
    
    	// Since there is at least one item in the Selected Fields list,
    	// enable the Remove buttons
    	m_RemoveOne.EnableWindow();
    	m_RemoveAll.EnableWindow();	
    }
  54. Test your program and return to MSVC
  55. The < button works by removing, from the Selected Fields list box, the item that is selected. To do this, we first need to make sure that an item is selected. All the previous code took care of selecting an item in each list. The problem is that, this time, the selected item is removed. Therefore, we have the responsibility of selecting a new item.
    When an item has been removed, we will select the item that was under it. What if we had removed the item that was at the bottom of the list? In that case, we will select the new last item in the list.
    Press Ctrl + W
  56. In the Object IDs, click IDC_BTN_REMOVEONE
  57. In the Messages list, double-click BN_CLICKED
  58. Change the name of the function OnRemoveOne and press Enter
  59. Click Edit Code and implement the function as follows:
     
    void CTableWizardDlg::OnRemoveOne() 
    {
    	// Based on previous code, an item should be selected
    	// in the Selected Fields list
    	// Get the index of the currently selected item
    	int CurrentlySelected = m_SelectedFields.GetCurSel();
    	
    	// Remove the item from the list
    	m_SelectedFields.DeleteString(CurrentlySelected);
    
    	// Find out whether the list has just been emptied or not
    	// If the Selected Fields list is empty,
    	if( m_SelectedFields.GetCount() == 0 )
    	{
    		// then disable the Remove buttons
    		m_RemoveOne.EnableWindow(FALSE);
    		m_RemoveAll.EnableWindow(FALSE);
    	}
    	else // Since the Selected Fields list still contains something
    	{
    // Find out if the item that has just been removed was the last in the list
    		if( CurrentlySelected == m_SelectedFields.GetCount() )
    		{
    			// Select the last item in the list
    		m_SelectedFields.SetCurSel(m_SelectedFields.GetCount() - 1);
    		}
    		else // Otherwise
    		{
    		// Select the item that was above the one that was just deleted
    			m_SelectedFields.SetCurSel(CurrentlySelected);
    		}
    	}	
    }
  60. We also want the user to be able to remove an item by double-clicking it. This is the way it is done in Microsoft Access. Of course this is, not only optional, but also application independent because another program would have a different behavior when the item is double-clicked.
    Press Ctrl + W
  61. In the Object IDs list, click IDC_SELECTEDFIELDS
  62. In the Messages list, double-click LBN_DBLCLK
  63. Change the function name to OnDblClkSelectedFields and press Enter
  64. Click Edit Code and implement the function as follows:
     
    void CTableWizardDlg::OnDblClkSelectedFields() 
    {
    // When the user double-clicks an item in the Selected Fields list,
    	// behave as if the < button has been clicked
    	OnRemoveOne();	
    }
  65. Test your program and return to MSVC.
  66. The << button is used to simply empty the Selected Fields list. It doesn't perform any checking of any kind. The only thing we need to do is to disable the Remove buttons after the Selected Fields list has been emptied.
    Press Ctrl + W
  67. In the Object IDs list, click IDC_BTN_REMOVEALL
  68. In the Messages list, double-click BN_CLICKED
  69. Change the function name to OnRemoveAll and press Enter
  70. Click Edit Code and implement the function as follows:
     
    void CTableWizardDlg::OnRemoveAll() 
    {
    	m_SelectedFields.ResetContent();
    
    	// Since the Selected Fields list is now empty,
    	// disable the Remove buttons
    	m_RemoveOne.EnableWindow(FALSE);
    	m_RemoveAll.EnableWindow(FALSE);	
    }
  71. Test your program and return to MSVC.
  72. Since we, or I, decided not to increment the name of an already existing field in the Selected Fields list, we will solve this problem otherwise. In fact, we will solve two problems with one approach. We are going to allow the user to rename an item.
    Only an item from the Selected Fields list can be renamed. To do this, we will first make sure that an item is selected. If an item is selected, we will allow the user to click the Rename Field button. A dialog box will open with the name of the selected field. The user will have the option of changing the field's name or dismissing the operation. If the user clicked OK, we will change the old item with the new one and select the new item. This operation will not only allow the user to set an appropriate or friendlier name but can also let the user have fields such as Address1 and Address2.
  73. Press Ctrl + R to call the Insert Resource dialog box.
  74. Click Dialog and click New
  75. Press Alt + Enter to call the Properties dialog box.
  76. Change the ID of the dialog box to IDD_DLG_RENAMEFIELD and change its Caption to Rename Field
  77. Using the Toolbox, add an Edit Box control to the dialog box.
  78. Change its ID to IDC_EDIT_RENAME
  79. Add a Static Text with a Caption of Rename Field on the left side of the edit box.
  80. While the dialog is selected, on the main menu, click Layout -> Tab Order
  81. Click the edit box to make sure that it receives focus when the dialog is opened:
     
    Tab Control
  82. Right-click the edit box and click ClassWizard.
  83. On the Adding A Class dialog box, click the Create A New Class radio button and click OK
  84. Type the class name as CRenameFieldDlg
  85. Make sure the Base Class is CDialog and the Dialog ID is IDD_DLG_RENAMEFIELD. Click OK
  86. Click the Member Variables property sheet. Double-click IDC_EDIT_RENAME
  87. Set the name of the variable to m_RenameField
  88. Make sure its Category is Value and its Variable Type is CString. Click OK twice
  89. Open the main dialog box, the Table Wizard.
  90. Using the Toolbox, add a button identified as IDC_BTN_RENAMEFIELD
  91. Change its Caption to &Rename Field...
  92. Press Ctrl + W
  93. In the Member Variables property sheet, double-click IDC_BTN_RENAMEFIELD
  94. Change its name to m_RenameField
  95. Make sure its Category is Control and its Type is CButton. Click OK
  96. Click the Message Maps property sheet.
  97. In the Class Name combo box, select CTableWizardDlg (it should be selected by default, but just in case...).
    In the Object IDs list, click IDC_BTN_RENAMEFIELD
  98. In the Messages list box, double-click BN_CLICKED
  99. Change the name of the function to OnRenameField and press Enter.
  100. Click Edit Code.
    Since the Selected Fields list is empty when the dialog opens, the Rename Field button should be disabled. In fact the Rename Field button should be disabled whenever the Selected Field list box is empty or not item is selected in the Selected Fields list.
  101. Make the following changes to the whole file:
     
    // TableWizardDlg.cpp : implementation file
    //
    
    #include "stdafx.h"
    #include "TableWizard.h"
    #include "TableWizardDlg.h"
    #include "RenameFieldDlg.h"
    
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;
    #endif
    
    /////////////////////////////////////////////////////////////////////////////
    // CAboutDlg dialog used for App About
    
    class CAboutDlg : public CDialog
    {
    public:
    	CAboutDlg();
    
    // Dialog Data
    	//{{AFX_DATA(CAboutDlg)
    	enum { IDD = IDD_ABOUTBOX };
    	//}}AFX_DATA
    
    	// ClassWizard generated virtual function overrides
    	//{{AFX_VIRTUAL(CAboutDlg)
    	protected:
    	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
    	//}}AFX_VIRTUAL
    
    // Implementation
    protected:
    	//{{AFX_MSG(CAboutDlg)
    	//}}AFX_MSG
    	DECLARE_MESSAGE_MAP()
    };
    
    CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
    {
    	//{{AFX_DATA_INIT(CAboutDlg)
    	//}}AFX_DATA_INIT
    }
    
    void CAboutDlg::DoDataExchange(CDataExchange* pDX)
    {
    	CDialog::DoDataExchange(pDX);
    	//{{AFX_DATA_MAP(CAboutDlg)
    	//}}AFX_DATA_MAP
    }
    
    BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
    	//{{AFX_MSG_MAP(CAboutDlg)
    		// No message handlers
    	//}}AFX_MSG_MAP
    END_MESSAGE_MAP()
    
    /////////////////////////////////////////////////////////////////////////////
    // CTableWizardDlg dialog
    
    CTableWizardDlg::CTableWizardDlg(CWnd* pParent /*=NULL*/)
    	: CDialog(CTableWizardDlg::IDD, pParent)
    {
    	//{{AFX_DATA_INIT(CTableWizardDlg)
    		// NOTE: the ClassWizard will add member initialization here
    	//}}AFX_DATA_INIT
    	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
    }
    
    void CTableWizardDlg::DoDataExchange(CDataExchange* pDX)
    {
    	CDialog::DoDataExchange(pDX);
    	//{{AFX_DATA_MAP(CTableWizardDlg)
    	DDX_Control(pDX, IDC_BTN_RENAMEFIELD, m_RenameField);
    	DDX_Control(pDX, IDC_BTN_SELECTONE, m_SelectOne);
    	DDX_Control(pDX, IDC_BTN_SELECTALL, m_SelectAll);
    	DDX_Control(pDX, IDC_BTN_REMOVEONE, m_RemoveOne);
    	DDX_Control(pDX, IDC_BTN_REMOVEALL, m_RemoveAll);
    	DDX_Control(pDX, IDC_SELECTEDFIELDS, m_SelectedFields);
    	DDX_Control(pDX, IDC_SAMPLEFIELDS, m_SampleFields);
    	DDX_Control(pDX, IDC_RDO_PERSONAL, m_SelectPersonal);
    	DDX_Control(pDX, IDC_RDO_BUSINESS, m_SelectBusiness);
    	DDX_Control(pDX, IDC_SAMPLE_TABLES, m_SampleTables);
    	//}}AFX_DATA_MAP
    }
    
    BEGIN_MESSAGE_MAP(CTableWizardDlg, CDialog)
    	//{{AFX_MSG_MAP(CTableWizardDlg)
    	ON_WM_SYSCOMMAND()
    	ON_WM_PAINT()
    	ON_WM_QUERYDRAGICON()
    	ON_BN_CLICKED(IDC_RDO_BUSINESS, OnSelectBusiness)
    	ON_BN_CLICKED(IDC_RDO_PERSONAL, OnSelectPersonal)
    	ON_BN_CLICKED(IDC_BTN_SELECTONE, OnSelectOne)
    	ON_LBN_SELCHANGE(IDC_SAMPLE_TABLES, OnSelectSampleTables)
    	ON_LBN_DBLCLK(IDC_SAMPLEFIELDS, OnDblClkSampleFields)
    	ON_BN_CLICKED(IDC_BTN_SELECTALL, OnSelectAll)
    	ON_BN_CLICKED(IDC_BTN_REMOVEONE, OnRemoveOne)
    	ON_LBN_DBLCLK(IDC_SELECTEDFIELDS, OnDblClkSelectedFields)
    	ON_BN_CLICKED(IDC_BTN_REMOVEALL, OnRemoveAll)
    	ON_BN_CLICKED(IDC_BTN_RENAMEFIELD, OnRenameField)
    	//}}AFX_MSG_MAP
    END_MESSAGE_MAP()
    
    /////////////////////////////////////////////////////////////////////////////
    // CTableWizardDlg message handlers
    
    BOOL CTableWizardDlg::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);
    		}
    	}
    
    	SetIcon(m_hIcon, TRUE);			// Set big icon
    	SetIcon(m_hIcon, FALSE);		// Set small icon
    	
    	// TODO: Add extra initialization here
    	// Select the Business radio button
    	m_SelectBusiness.SetCheck(1);
    
    	// Get the number of items in the array
    	SizeBusiness	= sizeof(Business) / sizeof(CString);
    	SizePersonal	= sizeof(Personal) / sizeof(CString);
    	SizeContacts	= sizeof(Contacts) / sizeof(CString);
    	SizeAddresses	= sizeof(Addresses) / sizeof(CString);
    	SizeEmployees	= sizeof(Business) / sizeof(CString);
    	SizeCustomers	= sizeof(Business) / sizeof(CString);
    	SizeVideoCollection = sizeof(VideoCollection) / sizeof(CString);
    	SizeCategories  = sizeof(Categories) / sizeof(CString);
    	SizeAuthors	= sizeof(Authors) / sizeof(CString);
    	SizeBooks	= sizeof(Books) / sizeof(CString);
    
    	// Fill out the Sample Tables list with the Business items
    	for(int i = 0; i < SizeBusiness; i++)
    			m_SampleTables.AddString(Business[i]);
    
    	// Select the first item in the Sample Tables list box
    	m_SampleTables.SetCurSel(0);
    
    	// Fill out the Sample Fields list box
    	for(int j = 0; j < SizeContacts; j++)
    		m_SampleFields.AddString(Contacts[j]);
    
    	// Select the first item in the Sample Fields list box
    	m_SampleFields.SetCurSel(0);
    
    	// Since the Selected Field list box is empty, disable the Remove buttons
    	m_RemoveOne.EnableWindow(FALSE);
    	m_RemoveAll.EnableWindow(FALSE);
    
    	// The Selected Fields list is empty.
    	// There is not need for the Rename Field button
    	m_RenameField.EnableWindow(FALSE);
    
    	return TRUE;  // return TRUE  unless you set the focus to a control
    }
    
    void CTableWizardDlg::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 CTableWizardDlg::OnPaint() 
    {
    	if (IsIconic())
    	{
    		CPaintDC dc(this); // device context for painting
    
    		SendMessage(WM_ICONERASEBKGND, (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();
    	}
    }
    
    HCURSOR CTableWizardDlg::OnQueryDragIcon()
    {
    	return (HCURSOR) m_hIcon;
    }
    
    void CTableWizardDlg::OnSelectBusiness() 
    {
    	// Empty the lists
    	m_SampleTables.ResetContent();
    	m_SampleFields.ResetContent();
    
    	// Fill out the list with Business items
    	for(int i = 0; i < SizeBusiness; i++)
    		m_SampleTables.AddString(Business[i]);
    	m_SampleTables.SetCurSel(0);
    
    	// Fill out the Sample Fields list and select the first item
    	for(int j = 0; j < SizeContacts; j++)
    		m_SampleFields.AddString(Contacts[j]);
    	m_SampleFields.SetCurSel(0);
    }
    
    void CTableWizardDlg::OnSelectPersonal() 
    {
    	// Empty the lists
    	m_SampleTables.ResetContent();
    	m_SampleFields.ResetContent();
    
    	// Fill out the list
    	for(int i = 0; i < SizePersonal; i++)
    			m_SampleTables.AddString(Personal[i]);
    	m_SampleTables.SetCurSel(0);
    
    	// Fill out the Sample Fields list and select the first item
    	for(int j = 0; j < SizeAddresses; j++)
    		m_SampleFields.AddString(Addresses[j]);
    	m_SampleFields.SetCurSel(0);
    }
    
    void CTableWizardDlg::OnSelectSampleTables() 
    {
    	// Before filling out the Sample Fields list box, empty it first
    	m_SampleFields.ResetContent();
    
    	// This string variable will identify the selected table
    	CString ItemSelected;
    	
    	// Get the name of the item selected in the Sample Tables list box
    	// and store it in the CString variable declared above
    	m_SampleTables.GetText(m_SampleTables.GetCurSel(), ItemSelected);
    	
    	// Fill out the Sample Fields list box according to the selected table
    	if( ItemSelected == "Contacts" )
    	{
    		for(int i = 0; i < SizeContacts; i++)
    			m_SampleFields.AddString(Contacts[i]);
    	}
    	else if( ItemSelected == "Customers" )
    	{
    		for(int i = 0; i < SizeCustomers; i++)
    			m_SampleFields.AddString(Customers[i]);
    	}
    	else if( ItemSelected == "Employees" )
    	{
    		for(int i = 0; i < SizeEmployees; i++)
    			m_SampleFields.AddString(Employees[i]);
    	}
    	else if( ItemSelected == "Addresses" )
    	{
    		for(int i = 0; i < SizeAddresses; i++)
    			m_SampleFields.AddString(Addresses[i]);
    	}
    	else if( ItemSelected == "VideoCollection" )
    	{
    		for(int i = 0; i < SizeVideoCollection; i++)
    			m_SampleFields.AddString(VideoCollection[i]);
    	}
    	else if( ItemSelected == "Categories" )
    	{
    		for(int i = 0; i < SizeCategories; i++)
    			m_SampleFields.AddString(Categories[i]);
    	}
    	else if( ItemSelected == "Authors" )
    	{
    		for(int i = 0; i < SizeAuthors; i++)
    			m_SampleFields.AddString(Authors[i]);
    	}
    	else if( ItemSelected == "Books" )
    	{
    		for(int i = 0; i < SizeBooks; i++)
    			m_SampleFields.AddString(Books[i]);
    	}
    	else // If we didn't create a list for the selected table, show nothing
    		m_SampleFields.ResetContent();
    
    	// Select the first item, if any, in the Sample Fields list box
    	m_SampleFields.SetCurSel(0);		
    }
    
    void CTableWizardDlg::OnSelectOne() 
    {
    	// Variable that identifies what item is selected in the sample fields
    	CString SourceSelected;
    
    	// Find out what item is selected
    	// Store it in the above variable
    	m_SampleFields.GetText(m_SampleFields.GetCurSel(), SourceSelected);
    	
    	// Find out if the Selected Fields list is empty
    	if( m_SelectedFields.GetCount() == 0 )
    	{
    		// Since the list is empty, add the selected item
    		m_SelectedFields.AddString(SourceSelected);
    		// Select the newly added item
    		m_SelectedFields.SetCurSel(0);
    	}
    	else // Since the list is not empty
    	{
    		// Look for the selected item in the Selected Fields list
    		int Found = m_SelectedFields.FindString(0, SourceSelected);
    
    		// If the item is not yet in the Selected Fields list, prepare to add it
    		if( Found == -1 )
    		{
    			// Because there is always an item selected in any of our list,
    			// Get the index of the currently selected item
    			int CurrentlySelected = m_SelectedFields.GetCurSel();
    
    			// Add the new item under the selected one
    			m_SelectedFields.InsertString(CurrentlySelected + 1, SourceSelected);
    
    			// Selected the newly added item
    			m_SelectedFields.SetCurSel(CurrentlySelected + 1);
    		}
    	}
    
    	// Since an item has been selected, enable the Remove buttons
    	m_RemoveOne.EnableWindow();
    	m_RemoveAll.EnableWindow();
    	
    	// Since an item is selected, enable the Rename button
    	m_RenameField.EnableWindow();
    }
    
    void CTableWizardDlg::OnDblClkSampleFields() 
    {
    	// When the user double-clicks an item in the Sample Fields list
    	// behave as if the Select One button was clicked
    	OnSelectOne();	
    }
    
    void CTableWizardDlg::OnSelectAll() 
    {
    	// This string will represent an item in the Sample Field list
    	CString Item;
    
    	// This "for" loop will be used to navigate the Sample Fields list
    	for(int i = 0; i < m_SampleFields.GetCount(); i++)
    	{
    		// Consider an item in the Sample Fields list
    		// Store it in the above declared Item variable
    		m_SampleFields.GetText(i, Item);
    
    		// Look for the item in the Selected Fields list
    		int Found = m_SelectedFields.FindString(0, Item);
    
    	// If the item is not yet in the Selected Fields list, prepare to add it
    		if( Found == -1 )
    		{
    			// Add the new item at the end of the Selected Fields list
    			m_SelectedFields.AddString(Item);
    
    			// Selected the last item of the Selected Fields list
    			m_SelectedFields.SetCurSel(m_SelectedFields.GetCount() - 1);
    		}
    	}
    
    	// Since there is at least one item in the Selected Fields list
    	// enable the Remove buttons
    	m_RemoveOne.EnableWindow();
    	m_RemoveAll.EnableWindow();
    	
    	// Enable the Rename button
    	m_RenameField.EnableWindow();
    }
    
    void CTableWizardDlg::OnRemoveOne() 
    {
    	// Based on previous code, an item should be selected
    	// in the Selected Fields list
    	// Get the index of the currently selected item
    	int CurrentlySelected = m_SelectedFields.GetCurSel();
    	m_SelectedFields.DeleteString(CurrentlySelected);
    
    	// Find out whether the list has just been emptied or not
    	// If the Selected Fields list is empty
    	if( m_SelectedFields.GetCount() == 0 )
    	{
    		// disable the Remove buttons
    		m_RemoveOne.EnableWindow(FALSE);
    		m_RemoveAll.EnableWindow(FALSE);
    		//and disable the Rename button
    		m_RenameField.EnableWindow(FALSE);
    	}
    	else // Since the Selected Fields list still contains something
    	{
    	// Find out if the item that has just been removed was the last in the list
    		if( CurrentlySelected == m_SelectedFields.GetCount() )
    		{
    			// Selected the last item in the list
    		m_SelectedFields.SetCurSel(m_SelectedFields.GetCount() - 1);
    		}
    		else // Otherwise
    		{
    		// Select the item that was above the one that was just deleted
    			m_SelectedFields.SetCurSel(CurrentlySelected);
    		}
    	}	
    }
    
    void CTableWizardDlg::OnDblClkSelectedFields() 
    {
    	// When the user double-clicks an item in the Selected Fields list
    	// behave as if the Remove One button has been clicked
    	OnRemoveOne();	
    }
    
    void CTableWizardDlg::OnRemoveAll() 
    {
    	m_SelectedFields.ResetContent();
    
    	// Since the Selected Fields list is now empty,
    	// disable the Remove buttons
    	m_RemoveOne.EnableWindow(FALSE);
    	m_RemoveAll.EnableWindow(FALSE);
    	// and enable the Rename button
    	m_RenameField.EnableWindow(FALSE);
    }
    
    void CTableWizardDlg::OnRenameField() 
    {
    	// Declare a variable to store the currently selected item
    	CString SelectedItem;
    
    	// Get the index of the currently selected item
    	int CurrentlySelected = m_SelectedFields.GetCurSel();
    
    	// The dialog box that will be called
    	CRenameFieldDlg Dlg;
    
    	// Retrieve the string of the currently selected item
    	// and store it in the SelectedItem variable
    	m_SelectedFields.GetText(m_SelectedFields.GetCurSel(), SelectedItem);
    
    	// Put the selected string int the Edit box of the Rename Field dialog
    	Dlg.m_RenameField.Format("%s", SelectedItem);
    
    	// Now call the Rename Field dialog box
    	// Show the field to the user
    	// Find out if the user clicked OK when dismissing the dialog box
    	if( Dlg.DoModal() )
    	{
    		// Since the user has clicked OK on the Rename Field dialog box,
    		// before proceeding, delete the old string from the list
    		m_SelectedFields.DeleteString(CurrentlySelected);
    
    		LPTSTR NewItem;
    
    		NewItem = Dlg.m_RenameField.GetBuffer(10);
    
    		// Look for the new item in the Selected Fields list
    		int Found = m_SelectedFields.FindString(0, NewItem);
    
    	// If the item is not yet in the Selected Fields list, prepare to add it
    		if( Found == -1 )
    		{
    			// Add the new item under the selected one
    			m_SelectedFields.InsertString(CurrentlySelected, NewItem);
    
    			// Select the newly added item
    			m_SelectedFields.SetCurSel(CurrentlySelected);
    		}
    
    		Dlg.m_RenameField.ReleaseBuffer();
    	}
    }
  102. Test your program
 

Home Copyright © 2002-2006 FunctionX FunctionX