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
|