Global Navigation Bar

MapInfo Products Knowledge Base


Product: MapX
Version: 3.0
Platform: All Win32 Platforms
Category: Code Samples

Summary:
Data binding techniques in C++.

Question:
How to bind data to a map in C++?

Answer:

Adding a MapInfo Native table:

static char BASED_CODE szDataFilter[] = "Map Data Files (*.txt)|*.txt|All Files (*.*)|*.*||";

// get the filename from the file open dialog
// the file must be in the format described above

void CMapxSampleView::OnMapAdddata()
{
HGLOBAL hGlobalData=NULL;
char *psz=NULL;


CFileDialog dlgFile(TRUE, "*.txt", NULL, 0, szDataFilter, this);

if (dlgFile.DoModal() == IDCANCEL)
return;

// read file into a string, and copy it to a global
// memory buffer

CFile fileData(dlgFile.GetPathName(), CFile::modeRead);
CString strBuffer;
fileData.Read(strBuffer.GetBuffer(fileData.GetLength() + 1), fileData.GetLength());
strBuffer.ReleaseBuffer(fileData.GetLength() + 1);
fileData.Close();


hGlobalData = GlobalAlloc(GMEM_MOVEABLE, strBuffer.GetLength()+1);
psz=(
char *)GlobalLock(hGlobalData);
strcpy(psz, strBuffer);
GlobalUnlock(hGlobalData);


short Type;
VARIANT SourceData;
VARIANT Name;
VARIANT GeoField;
VARIANT SecondaryGeoField;
VARIANT BindLayerName;
VARIANT Fields;
CString strName= "TestData";


// set up optional parameters

// will not be used
SecondaryGeoField.vt = VT_ERROR;
SecondaryGeoField.scode = DISP_E_PARAMNOTFOUND;


// let mapx auto detect geofield
GeoField.vt = VT_ERROR;
GeoField.scode = DISP_E_PARAMNOTFOUND;


// let mapx find which layer to bind to
BindLayerName.vt = VT_ERROR;
BindLayerName.scode = DISP_E_PARAMNOTFOUND;


// use all fields with defaults
Fields.vt = VT_ERROR;
Fields.scode = DISP_E_PARAMNOTFOUND;


// set the name of our dataset
Name.vt = VT_BSTR;
Name.bstrVal = strName.AllocSysString();


// set up source data - no error checking on alloc
Type = miDataSetGlobalHandle;
SourceData.vt = VT_I4;
SourceData.lVal = (long)hGlobalData;


try {
// now add the dataset to the datasets collection
CMapXDataset ds = m_ctrlMapX.GetDatasets().Add(Type, SourceData, Name, GeoField, SecondaryGeoField, BindLayerName, Fields, COptionalVariant());

// zoom out to see any new layers that are added
//OnViewViewentiremap();
}
catch (COleDispatchException *e) {
e->ReportError();
e->Delete();
}


}

From a map layer:

void CMapxSampleView::OnDatasestFromLayer()
{
try {
CMapXLayer layer = m_ctrlMapX.GetLayers().Item("USA");


VARIANT vtLayer;
vtLayer.vt = VT_DISPATCH;
vtLayer.pdispVal = layer.m_lpDispatch;


CMapXDataset dataSet = m_ctrlMapX.GetDatasets().Add(miDataSetLayer, vtLayer, "USA Layer");
}
// end-of-try
catch (COleDispatchException *e) {
e->ReportError();
e->Delete();
}
catch (COleException *e) {
e->ReportError();
e->Delete();
}
}


Using a DAO Dataset:

// The CUSARecordset class' GetDefaultDBName()
// method brings up a file picker for finding
// the mapstats.mdb file.

void CMapxSampleView::OnMapAdddaodata()
{
try {
if (!m_daoUSCust.IsOpen()) {
m_daoUSCust.Open();
}
}
catch (CDaoException *e) {
e->ReportError();
e->Delete();
return;
}


short Type;
VARIANT SourceData;
VARIANT Name;
VARIANT GeoField;
VARIANT BindLayerName;
VARIANT Fields;
CString strName= "DAO US Customers";


// set up optional parameters
// could also use COptionalVariant class from mapx.h


// will not be used
COptionalVariant SecondaryGeoField;


// let mapx auto detect geofield
// this is the same as using COptionalVariant

GeoField.vt = VT_BSTR;
GeoField.bstrVal = CString("STATE").AllocSysString();


// let mapx find which layer to bind to
BindLayerName.vt = VT_BSTR;
BindLayerName.bstrVal = CString("USA").AllocSysString();


// use all fields with defaults
Fields.vt = VT_ERROR;
Fields.scode = DISP_E_PARAMNOTFOUND;


// set the name of the dataset
Name.vt = VT_BSTR;
Name.bstrVal = strName.AllocSysString();


// set up source data
// Note: it is best to keep the dao recordset around until mapx is done with it
Type = miDataSetDAO;
SourceData.vt = VT_DISPATCH;
SourceData.pdispVal = m_daoUSCust.m_pDAORecordset;


try {
// now add the dataset to the datasets collection
CMapXDataset ds = m_ctrlMapX.GetDatasets().Add(Type, SourceData,

Name, GeoField, SecondaryGeoField, BindLayerName, Fields, COptionalVariant());
}
catch (COleDispatchException *e) {
e->ReportError();
e->Delete();
}
}


Here is an ODBC data binding routines, which uses the US_Cust table in the MapStats Access database:

Normal Fields:

void CMapxSampleView::OnOdbcNormalFields()
{
CMapXDatasets ds = m_ctrlMapX.GetDatasets();

short Type;
VARIANT SourceData;
VARIANT Name;
VARIANT GeoField;
VARIANT SecondaryGeoField;
VARIANT BindLayerName;
VARIANT Fields;
CString strName= "ODBCNormalFields";


// will not be used
SecondaryGeoField.vt = VT_ERROR;
SecondaryGeoField.scode = DISP_E_PARAMNOTFOUND;


// want to bind to STATE col
GeoField.vt = VT_BSTR;
GeoField.bstrVal = CString("STATE").AllocSysString();


// and the USA layer
BindLayerName.vt = VT_BSTR;
BindLayerName.bstrVal = CString("USA").AllocSysString();


// limit fields to the geocolumns and 1 attribute cols
CMapXFields fields;
fields.CreateDispatch(fields.GetClsid());
fields.Add("STATE");
fields.Add("ORDER_AMT");

Fields.vt = VT_DISPATCH;
Fields.pdispVal = fields.m_lpDispatch;


// set the name of the dataset
Name.vt = VT_BSTR;
Name.bstrVal = strName.AllocSysString();


CMapXODBCQueryInfo ODBCParam;

try {
// set up source data - no error checking on alloc
Type = miDataSetODBC;


ODBCParam.CreateDispatch("MapX.ODBCQueryInfo.3");

ODBCParam.SetConnectString("ODBC;");
ODBCParam.SetSqlQuery("Select * From US_CUST");
// this assumes you have an Access DataSource called MapStatsV3 pointing
// to the MapStats.mdb that ships with MapX. If the DataSource param is left
// out, the user will be prompted for an ODBC datasource.
ODBCParam.SetDataSource("MapStatsV3");


SourceData.vt = VT_DISPATCH;
SourceData.pdispVal = ODBCParam.m_lpDispatch;


ds.Add(Type, SourceData, Name, GeoField, SecondaryGeoField, BindLayerName,
Fields, COleVariant((long)m_bODBCDynamic));
}
catch (COleDispatchException *e) {
e->ReportError();
e->Delete();
}
catch (COleException *e) {
e->ReportError();
e->Delete();
}
}


XY Binding:

void CMapxSampleView::OnOdbcXybind()
{
CMapXDatasets ds = m_ctrlMapX.GetDatasets();

short Type;
VARIANT SourceData;
VARIANT Name;
VARIANT GeoField;
VARIANT SecondaryGeoField;
VARIANT BindLayer;
CMapXBindLayer bindLayer;
VARIANT Fields;
CString strName= "ODBCXYDataset";


// will not be used
SecondaryGeoField.vt = VT_ERROR;
SecondaryGeoField.scode = DISP_E_PARAMNOTFOUND;


// use LASTNAME as unique id in new layer - should have a custid
GeoField.vt = VT_BSTR;
GeoField.bstrVal = CString("LNAME").AllocSysString();


// use all fields with defaults
Fields.vt = VT_ERROR;
Fields.scode = DISP_E_PARAMNOTFOUND;


// set the name of our dataset
Name.vt = VT_BSTR;
Name.bstrVal = strName.AllocSysString();


CMapXODBCQueryInfo ODBCParam;

try {
// set up source data - no error checking on alloc
Type = miDataSetODBC;


ODBCParam.CreateDispatch("MapX.ODBCQueryInfo.3");

ODBCParam.SetConnectString("ODBC;");
ODBCParam.SetSqlQuery("Select * From US_CUST");
// this assumes there is an Access DataSource called MapStatsV3 pointing
// to the MapStats.mdb that ships with MapX. If the DataSource param is left
// out, the user will be prompted for an ODBC datasource.

ODBCParam.SetDataSource("MapStatsV3");


SourceData.vt = VT_DISPATCH;
SourceData.pdispVal = ODBCParam.m_lpDispatch;


// now set up binding
bindLayer.CreateDispatch(bindLayer.GetClsid());
bindLayer.SetLayerName("Customers");
bindLayer.SetRefColumn1("X");
bindLayer.SetRefColumn2("Y");
bindLayer.SetLayerType(miBindLayerTypeXY);


BindLayer.vt = VT_DISPATCH;
BindLayer.pdispVal = bindLayer.m_lpDispatch;


ds.Add(Type, SourceData, Name, GeoField, SecondaryGeoField, BindLayer, Fields, COleVariant((long)m_bODBCDynamic));
}
catch (COleDispatchException *e) {
e->ReportError();
e->Delete();
}
catch (COleException *e) {
e->ReportError();
e->Delete();
}
}


Here is an Unbound Dataset routine:

void CMapxSampleView::OnMapAddunbounddata()
{
try {
COleVariant vtFieldType ((
long)miTypeNumeric);
COleVariant vtFieldAggr ((
long)miAggregationSum);
CMapXFields fields;


fields.CreateDispatch (fields.GetClsid());
fields.Add("STATE", "STATE");
fields.Add(COleVariant("POP"), COleVariant("POP"), vtFieldAggr, vtFieldType );


VARIANT vtFields;
vtFields.vt = VT_DISPATCH;
vtFields.pdispVal = fields.m_lpDispatch;


// and, finally, make the request to add the "unbound dataset"
// this will trigger the request to fetch the data

CMapXDataset dataSet = m_ctrlMapX.GetDatasets().Add(miDataSetUnbound,COptionalVariant(),
COleVariant("UnboundData"), COleVariant(1L), COptionalVariant(), COleVariant("USA"),
vtFields, COptionalVariant());
}
// end-of-try
catch (COleDispatchException *e) {
e->ReportError();
e->Delete();
}
catch (COleException *e) {
e->ReportError();
e->Delete();
}


}

// this example just uses hard coded values for 2 states
// any data can be used

static TCHAR *szUnboundData[2][2] = { _T("NY"), _T("15000000"), _T("MA"), _T("11500000") };

void CMapxSampleView::OnRequestDataMap(LPCTSTR DataSetName, long Row, short Field, VARIANT FAR* Value, BOOL FAR* Done)
{
TRACE("Unbound data request for layer: '%s', row, col: %d %d\n", DataSetName, Row, Field);


if (Row >= 1 && Row <= 2) {
CString strVal = szUnboundData[Row-1][Field-1];
Value->vt = VT_BSTR;
Value->bstrVal = strVal.AllocSysString();
*Done = FALSE;
}
else {
*Done = TRUE;
}
}


ODBC PointRef dataset:

void CMapxSampleView::OnOdbcZipcode()
{
CMapXDatasets ds = m_ctrlMapX.GetDatasets();

short Type;
VARIANT SourceData;
VARIANT Name;
VARIANT GeoField;
VARIANT SecondaryGeoField;
VARIANT BindLayer;
CMapXBindLayer bindLayer;
VARIANT Fields;
CString strName= "ODBCZipDataset";


// will not be used
SecondaryGeoField.vt = VT_ERROR;
SecondaryGeoField.scode = DISP_E_PARAMNOTFOUND;


// use zipcode as unique id in new layer
GeoField.vt = VT_BSTR;
GeoField.bstrVal = CString("ZIP").AllocSysString();


// use all fields with defaults
Fields.vt = VT_ERROR;
Fields.scode = DISP_E_PARAMNOTFOUND;


// set the name of the dataset
Name.vt = VT_BSTR;
Name.bstrVal = strName.AllocSysString();


CMapXODBCQueryInfo ODBCParam;

try {
// set up source data - no error checking on alloc
Type = miDataSetODBC;


ODBCParam.CreateDispatch("MapX.ODBCQueryInfo.3");

ODBCParam.SetConnectString("ODBC;");
ODBCParam.SetSqlQuery("Select * From US_CUST");
// this assumes there is an Access DataSource called MapStatsV3 pointing
// to the MapStats.mdb that ships with MapX. If the DataSource param is left
// out, the user will be prompted for an ODBC datasource.

ODBCParam.SetDataSource("MapStatsV3");


SourceData.vt = VT_DISPATCH;
SourceData.pdispVal = ODBCParam.m_lpDispatch;


// now set up binding
bindLayer.CreateDispatch(bindLayer.GetClsid());
bindLayer.SetReferenceLayer("ZIPCODES.TAB");
bindLayer.SetLayerName("CustByZip");
bindLayer.SetRefColumn1("ZIP");
bindLayer.SetLayerType(miBindLayerTypePointRef);


BindLayer.vt = VT_DISPATCH;
BindLayer.pdispVal = bindLayer.m_lpDispatch;


ds.Add(Type, SourceData, Name, GeoField, SecondaryGeoField,
BindLayer, Fields, COleVariant((long)m_bODBCDynamic));
}
catch (COleDispatchException *e) {
e->ReportError();
e->Delete();
}
catch (COleException *e) {
e->ReportError();
e->Delete();
}

}




Last Modified: 03/26/1999 12:43:15 PM
Global Navigation Bar