DAO ComboBox

If you are working with relational databases you will often encounter the following problem: You've got a source table (for example a list of customers) and a target table (for example a bill). The target table contains an ID of the source table and you want to have a ComboBox to display the customer name but it should return the customers ID to the the dialog or form it is nested in. To reach this you often have to write a lot of code.

The CDaoComboBox class covers this problem. It should work with every CDaoRecordset as datasource and every dialog or form. And the best: you just need one or two lines of code to use it !

All you have to do is:
1) Add the CDaoComboBox class to your project.
2) Add a ComboBox control to your dialog or form.
3) Associate the control with CDaoComboBox via class wizard.
4) Initialize the control in the OnInitDialog() method of your dialog or the OnInitialUpdate() method of your form view (only one line of code ! See example below) with a pointer to the source recordset, the display field name and the return field name.
5) If the data type of the variable to store the result code is CString you can associate the control to this variable via class wizard. If it is not (in the example below it's a long value) you need to manually add a DDX funtion to the DoDataExchange() method of your dialog or form view (again only one line of code - the example below).

If you need to update the data displayed in the ComboBox (for example after the contents of the source table have changed) call CDaoComboBox::Fill()


The only method of the CDaoComboBox class you really need is Init(). It has the following syntax:


void Init(CDaoRecordset * pSet, CString strDispField, CString strReturnField, bool bIsRecordsetConstant = true)

Parameters:
pSet:
pointer to the source CDaoRecordset containing the display and return fields.
strDispField:
name of the field to display to the user.
strReturnField:
name of the field whichs value to return to the dialog or form.
bIsRecordsetConstant:
- true (default): the source recordset is queried only once and the content of the ComboBox remains constant for its lifetime.
- false: the source recordset is requeried every time the return value is set by the dialog or form (every time when a WM_SETTEXT message is sent to the ComboBox).

Remarks:
- If pSet is already opened, you have to close it manually. If it is not already opened, it will be automatically closed and it's memory will be deallocated when the ComboBox is destroyed.
- You can set the m_strFilter or m_strSort member variables of pSet if you need to.

----

Example for using:


[ConTestView.h]
#include "DaoComboBox.h"	// include the class header in your dialog or form view header
[...]
CDaoComboBox m_Combo;	// generated by class wizard

[ConTestView.cpp]
#include "QuellenSet.h"	// CQuellen is a DaoRecordset containing the fields "ID" and "Name"
[...]

void CConTestView::DoDataExchange(CDataExchange* pDX)
{
	CDaoRecordView::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CConTestView)
	DDX_Control(pDX, IDC_COMBO, m_Combo);
	DDX_Control(pDX, IDC_VEKTOR, m_Vektor);
	DDX_Control(pDX, IDC_Vorname, m_Vorname);
	DDX_Control(pDX, IDC_GebDatum, m_GebDatum);
	DDX_Control(pDX, IDC_TELEFON, m_Telefon);
	DDX_Control(pDX, IDC_BETRAG, m_Betrag);
	DDX_FieldText(pDX, IDC_BETRAG, m_pSet->m_Kontostand, m_pSet);
	DDX_FieldText(pDX, IDC_GebDatum, m_pSet->m_GebDatum, m_pSet);
	DDX_FieldText(pDX, IDC_TELEFON, m_pSet->m_Telefon, m_pSet);
	DDX_FieldText(pDX, IDC_Vorname, m_pSet->m_Vorname, m_pSet);
	DDX_FieldText(pDX, IDC_VEKTOR, m_pSet->m_Vektor, m_pSet);
	DDV_MinMaxDouble(pDX, m_pSet->m_Vektor, -9999999.99, 9999999.99);
	//}}AFX_DATA_MAP
	DDX_FieldText(pDX, IDC_COMBO, m_pSet->m_QuelleID, m_pSet);
	// The return string of the ComboBox is associated with the variable "m_QuelleID" (data type: long) in the target recordset "m_pSet"
}

void CConTestView::OnInitialUpdate() {
	m_Combo.Init( new CQuellenSet, "Name", "ID");
	// The combobox is associated with DaoRecordset "CQuellenSet",
	// the field values of the field "Name" are displayed,
	// the field value of the field "ID" is returned to "m_pSet->m_QuelleID"

	// [...]
	m_pSet = &GetDocument()->m_conTestSet;
	CDaoRecordView::OnInitialUpdate();
}
[...]

That's all ! No code in the UpdateData() method or somewhere else is needed !!!

Downloads

Download demo project - 40 Kb
Download source - 3 Kb


Comments

  • Problem and possible fix

    Posted by jacobskjoet on 06/05/2004 07:56am

    Spotted a problem in the CDaoComboBox::gettext function, when there's no current selection. The problem does not show at first use but when the class is instantiated second time all sorts of funny things starts to happen :-)
     
    Replace first part with 
    
    int CurSel = GetCurSel();
    if (CurSel == CB_ERR) {
      strcpy( (char *)textbuffer,"");
      return 0;
    }
    CString text = * (CString*)GetItemDataPtr(CurSel);
    
    Regards Jacob

    Reply
  • Help Me i still don't know

    Posted by Legacy on 08/02/2002 12:00am

    Originally posted by: Jeff

    I mean i got a DAO database *.mdb and i want to attach a table from another DAO database... How to do it ... can you show me the code... I used the CDaoTableDef::Create function to attach a table from another database but error occur( No installed ISAM )... what happen ... the MSDN show me that i can append a table from the ::Create function but i can't figure it out... Help

    Reply
  • How to attach table from another database

    Posted by Legacy on 08/01/2002 12:00am

    Originally posted by: Jeff

    How to append or attach a table from another database (*.mdb) Using DAO to a DAO database *.mdb

    Reply
  • How to read/write images and files from recordset

    Posted by Legacy on 07/24/2002 12:00am

    Originally posted by: LKP

    How to read/write images and files from recordset , pls help

    Reply
  • What language are all control Properties set to???(menu strings etc>>)

    Posted by Legacy on 12/07/2000 12:00am

    Originally posted by: Jeff Royle

    I tried changing all the control properties to English and I still get German or whatever it is???

    Reply
  • Very Cool!

    Posted by Legacy on 10/16/2000 12:00am

    Originally posted by: Craig Doggett

    Very Cool! Using it with Visual C++ 6.0 and it works great and was very easy to implement! Good Job!

    Reply
  • Demo program crash!

    Posted by Legacy on 03/27/2000 12:00am

    Originally posted by: Serrand

    I can't execute the demo program:
    
    

    It crash in :

    void AFXAPI AfxSetWindowText(HWND hWndCtrl, LPCTSTR lpszNew)

    at:

    if (nNewLen > _countof(szOld) ||
    ::GetWindowText(hWndCtrl, szOld, _countof(szOld)) != nNewLen ||
    lstrcmp(szOld, lpszNew) != 0)

    Reply
  • Crash when execute

    Posted by Legacy on 01/05/2000 12:00am

    Originally posted by: Marco Hern�ndez

    Your code compiles fine (VC 5). But when I try to run it crashes, invalid operation. Why???

    Reply
  • Small Bug ....

    Posted by Legacy on 12/14/1999 12:00am

    Originally posted by: Marco Freudenberger

    I found a small bug in my class:
    
    

    if the return value is longer than the display value,
    the return value is not correct. This is because i did not
    handle the WM_GETTEXTLENGTH message, that prepares the
    textbuffer for the return value.

    small changes in two methods will solve the problem:

    ------------------------------

    LRESULT CDaoComboBox::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) {
    // catch WM_GETTEXT and WM_SETTEXT to override standard behavior
    switch (message) {
    case WM_GETTEXTLENGTH:
    case WM_GETTEXT:
    return getText( wParam, lParam);
    case WM_SETTEXT:
    return setText( (LPCTSTR)lParam );
    default:
    return CComboBox::WindowProc(message, wParam, lParam);
    }
    }

    DWORD CDaoComboBox::getText(WPARAM maxLength, LPARAM textbuffer) {
    // return the associates return-value (as string)
    if ( GetCurSel() == CB_ERR ) {
    // nothing is selected
    return 0;
    }
    CString text = * (CString*)GetItemDataPtr(GetCurSel());

    if (textbuffer) {
    // if textbuffer is true, the method is called via WM_GETTEXT message
    if ( (maxLength-1) < (WPARAM)text.GetLength())
    text = text.Left(maxLength-1);
    strcpy( (char *)textbuffer, text );
    }
    // otherwise it is called via WM_GETTEXTLENGTH and only the length of the text is needed
    return text.GetLength();
    }

    Reply
  • Cool

    Posted by Legacy on 12/13/1999 12:00am

    Originally posted by: GT

    It is just what I was forced to develop, so it saved me some work. But, what about CRecordset, instead of CDaoRecordset. Will it work?

    Thanks

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: December 11, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT Market pressures to move more quickly and develop innovative applications are forcing organizations to rethink how they develop and release applications. The combination of public clouds and physical back-end infrastructures are a means to get applications out faster. However, these hybrid solutions complicate DevOps adoption, with application delivery pipelines that span across complex hybrid cloud and non-cloud environments. Check out this …

  • CentreCorp is a fully integrated and diversified property management and real estate service company, specializing in the "shopping center" segment, and is one of the premier retail service providers in North America. Company executives travel a great deal, carrying a number of traveling laptops with critical current business data, and no easy way to back up to the network outside the office. Read this case study to learn how CentreCorp implemented a suite of business continuity services that included …

Most Popular Programming Stories

More for Developers

RSS Feeds