Click here to Skip to main content
Click here to Skip to main content

The Ultimate Grid Datasources

By , 24 Aug 2007
 

Visit the Ultimate Grid main page for an overview and configuration guide to the Ultimate Grid library.

Contents

Introduction

One of the nice design features of the Ultimate Grid is the abstraction of the data layer from the presentation layer through the use of a base data source class. The CUGDataSource class abstracts all functions relating to a data source. This design allows for a high degree of code reuse, and allows tremendous flexibility in Ultimate Grid's implementation, allowing many different types of data sources to be used in combination, or interchangeably, without the need to re-code the inner workings of the grid or your application.

Most developers will begin with the default - the 'built in' "Memory Manager" (CUGMem) data source class, which allows for cell objects to be stored in the grid for display, and retrieved for manipulation. CUGMem is derived from CUGDataSource.

Up to 64000 CUGDataSource derived classes may be attached to each CUGCtrl class.

Why Use a Custom DataSource?

Dynamic Loading of Cell Information

You may wish to use a derived CUGDataSource class for loading cell information dynamically. Dynamic loading of cell information greatly improves performance for large tables, reduces memory requirements, and allows the grid to be displayed on-screen instantaneously.

Serialization

You may have a file which contains data with mark up to display and edit - XML would be a good example.

Incorporating Data Access APIs

Many Microsoft and 3rd party database implementations supply C/C++ interfaces to directly invoke SQL queries and access the result sets returned. This can allow for fully dynamic identification of columns, column types, and an efficient dynamic display of both static and dynamic result sets.

Pre-built DataSources and Examples

Many pre-defined CUGDataSource objects are included with Ultimate Grid:

ADO CADOImpDatasource

This datasource wraps the Active Data Objects interface, which in turn layers OLE DB.

Files:
DataSources\ADO\ADOImpDatasource.cpp ADOImpDatasource.h

Samples:
DataSources\ADO\ADODataSource\
DataSources\ADO\ADO Sample\

Array CUGCBArrayDataSource

An example of using a simple byte array as a datasource - the Dumper sample loads a file as a binary array and displays a hex/text dump.

Files:
DataSources\Array\UGCBADSC.cpp UGCBADSC.h

Sample:
DataSources\Array\Dumper3\

DAO CUGDAODataSource

The DAO datasource maintains member CDaoDatabase, CDaoTableDef, CDaoQueryDef, CDaoRecordset, and CDaoFieldInfo objects to allow for dynamic loading of Microsoft Access database query result sets.

Support for transactions is available.

Implements sorting and find next (FindDialog) functionality.

Files:
DataSources\DAO\Ugdao.cpp Ugdao.h

Samples:
DataSources\DAO\DAO Sorting\
DataSources\DAO\MyAccess\

Additional:
DataSources\DAO\dao.htm
Delimited CUG_Delimitted

An example of a serializable datasource, the CUG_Delimited class can read CSV files etc. The delimiter character can be specified. Derived from CUGMem (the default memory based datasource for the grid).

Files:
DataSources\Delimited\UGdelim.cpp UGdelim.h

Sample:
DataSources\Delimited\Example\

Additional:
DataSources\delimited\ReadME.txt

Html CUG_HTML_DataSource

This data source handles importing simple HTML tables. It will skip over embedded tables to completely import the table. You can decided which of the outer most tables to import by passing a table number to the Open function.

Files:
DataSources\Html\UGHTML.cpp UGHTML.h

Sample:
DataSources\Html\htmlexam\

ODBC CUGODBCDatasource

The CUGODBCDatasource class includes a CUGRecordset class derived from CRecordset that uses the ODBC API directly to enable dynamic identification of table columns, types, etc.

Files:
DataSources\ODBC\ugrecset.cpp ugrecset.h UGODBC.CPP UGODBC.H

Samples:
DataSources\ODBC\odbcexam\
DataSources\ODBC\odbcexm2\

OLE DB CUG_OLEDB_DataSource

The OLE DB datasource and column binding classes can dynamically access database result sets through the OLE DB data interfaces.

Files:
DataSources\OleDB\binds.cpp binds.h ugoledb.cpp ugoledb.h

Sample:
DataSources\OleDB\Example\

XML CXMLParser

The XML datasource atypical of the classes described here, as is not derived from CUGDataSource. The CXMLParser class maintains a pointer to a grid object which it can populate with data and cell properties gleaned from an XML file, but the grid itself uses the default memory datasource.

This class has been updated for better rendering of Microsoft Excel xml attributes.

Files:
DataSources\XML\COXParser\*.*
DataSources\XML\XMLParser.cpp XMLParser.h

Sample:
DataSources\XML\XMLSample\

Creating Custom CUGDataSource Classes

Probably the most common need for a custom datasource is when dealing with a large amount of external data (for which you already have an interface) that can retrieve data based on a col and row vector, obviating the overhead that would be required in duplicating data items by preloading them through the SetCell interface of the grid.

Custom data sources can be engineered with as little as one virtual override of the GetCell() function. Depending upon your requirements, you may also wish to provide the data source class with the ability to write information back to the data source through the SetCell() function. Your data source class can also be responsible for reordering the data source based upon indices, calculating the total number of rows, calculating the number columns, determining the column headings, etc. You may provide as much or as little functionality as you require in your custom data source classes.

In a fully developed data source class special functions such as SetGridFromDataSource() can be added to allow the grid to automatically ask the data source for information on column titles, column types, formatting, etc., and automatically set the default grid and column cell objects with this information.

Once you have a CUGDatasource derived class in place, simply declare an instance in and call the grid's AddDatasource method to add it to the grid's array of known datasources. To set it as the current datasource for the grid, call SetDefDatasource with the index returned from AddDatasource. The grid will then query your GetCell method when drawing data.

For more on creating and using datasources with the Ultimate Grid, refer to the tutorials and class references in the compiled CHM help documentation.

History

Initial CodeProject release August 2007.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

The Ultimate Toolbox
Web Developer
Canada Canada
Member
Organisation
264 members

In January 2005, David Cunningham and Chris Maunder created TheUltimateToolbox.com, a new group dedicated to the continued development, support and growth of Dundas Software’s award winning line of MFC, C++ and ActiveX control products.
 
Ultimate Grid for MFC, Ultimate Toolbox for MFC, and Ultimate TCP/IP have been stalwarts of C++/MFC development for a decade. Thousands of developers have used these products to speed their time to market, improve the quality of their finished products, and enhance the reliability and flexibility of their software.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
BugCannot download the source code for this projectmemberMember 824623723 Nov '12 - 4:18 
When I try to download any of the three downloads it goes back to the article saying it wants to make sure I have the newest version or it shows a black console saying no ticket provided.
 
Please fix I need to construct a grid dynamically with the following features:
1. Unknown number of rows and columns
2. Scrolling
3. Headers that stay in place while scrolling.
4. Cells with letters colored in different colors.
5. Row back ground color depends on data in that row.
6. Movable columns.
7. Hidable rows.
 
Currently I have 1, 2, 4 and 5 but if I can define my own data source this can be converted to use the MVVM design pattern.
QuestionHow to make ID column not show and insert can generate a new ID valuemembermaplewang10 Jul '12 - 21:31 
for example I have a table including a ID column, It need not to be shown on the Grid, But if the Grid can add a new record, how can I added it with a new ID. I suppose it can be added by SQL line like:
 
INSERT INTO SalaryStatistics (ID,EmpId,iMonth,ItemId,Total) select iif(ISNULL(MAX(ID)),1,max(ID)+1) ,4,201207,1,5000 from SalaryStatistics
 
the sql code can work for access database.
I did not use auto generate function for ID, because it is not easy for ID replication.
GeneralMy vote of 5membermaplewang10 Jul '12 - 21:25 
Thanks it is a good tool.
QuestionHow to set top header rows number and join header cells in DataSource?membericeway16 Nov '09 - 17:39 
I load data from a customized MyDataSource class. It implements GetNumCols, GetNumRows, GetCell. It works well.
 
Now I want to use more complex top headers, with joined header cells. I noticed in MyCug class we can use SetTH_NumberRows to set multimple header rows and them use JoinCells to join them. But the DataSource Class doesn't have a "GetTh_NumberRows" method or something like that. So how could the MyCug knows there are 2 top header rows in the datasource?
 
The code I think it should be:
int MyDataSource::GetTH_NumberRows()
{
return 2;
}
 
int MyDataSource::GetCell(int iCol,long iRow,CUGCell *cell)
{
if(iRow==-2) // set top header cell joins
{
cell->SetJoinInfo(...);
}
...
}
 
Are there a right way to do that?
 
ice on my way

AnswerRe: How to set top header rows number and join header cells in DataSource?editorTim Deveaux17 Nov '09 - 8:48 
You might not be able to do this in OnGetCell because of the way the cells defer to the parent join on retrieval.
 
I haven't tested this, but here's something you might be able to try fairly quickly.
 
Before setting the new datasource as the default, set the top heading row count and implement the joining, text etc. needed for the top heading rows.
 
After switching to your datasource as the default, add some code to your datasource's GetCell for rows less than 0 that will call the control to get the data for the cell from the default CUGMem datasource.
 
Something like:
    if(row < 0) {
        // ds at index 0 is the default memory manager, CUGMem
        m_ctrl->GetDataSource(0)->GetCell(col,row,&cell);
        return UG_SUCCESS;
    }
Things like column widths will be controlled by the colInfo for each column, which will I think involves the default datasource, so set these after the switch.
 
My theory here is that by allowing the memory manger datasource to come into play the cells it stores should be able to retain the info on the joins.
 
Again, untried, but might not be too hard to implement and test.
 
Tim
GeneralCUGDatasource::Browse crash [modified]memberRymka5 Nov '09 - 3:10 
Hello,
 
I'm having problems with vs2008 and mssql2005 express.
 
When i try:
 
CUGODBCDatasource *m_odbc;
 
m_odbc->Browse(this->m_hWnd);
 
app crashes on Close() ugodbc.cpp 83 line.
 
if i use
 
CUGODBCDatasource m_odbc;
 
m_odbc.Browse(this->m_hWnd);
 
datasource dialog opens up, but when i select datasource i get "Buffer is too small" error after UGStr::tcscpy((LPTSTR)m_dsInfoArray[m_tableCount].remarks,255,(LPTSTR)szRemarks); on ugodbc.cpp 268 line
 
if i increase 255, app crashes after *m_odbc->GetConnectString() call.
 
odbc examples works fine. but if i try to recreate them in vs2008 project i get the same as above.
 
modified on Thursday, November 5, 2009 9:23 AM

GeneralDemo program "db7" (odbcexam2) crashesmemberJRCooper27 Oct '09 - 9:14 
Hello,
 
The following two changes prevent the demo program from crashing,
when the user tries to move to the right of the last column.
 
Change 1:
CString string;
	
// get the field info object from the recordset
SQLColumnInfo* cfi = m_Record->GetFieldInfo(col);
    
if (col == m_Record->m_nFields) return UG_SUCCESS;  //Add this line in UGODBC.CPP (line #589)

// if field is NULL, return " " in string 
if(m_Record->IsFieldNull(cfi->pValue)) {
------------------
change 2:
 
From:
	if (col <= (int)m_nFields)   //Change this line in UGRECSET.CPP (line #612)

To:
	if (col < (int)m_nFields)

QuestionHow to use a dynamical data source with a known row countmembericeway26 Oct '09 - 18:17 
Hi everyone.
 
I have my data in a self-defined data structure (like a memory db) and have a large count of rows, and the rows count is known. At the start, I load data in CMyCug::OnGetCell, the grid works well, the data is displayed without any delay.
 
Now I want to use a data source instead of loading data in CMyCug directly. But if MyDataSrc::GetNumRows returns the real count of rows, all cells will be loaded when setup the data source, and it costs seconds to show the grid. I noticed the implemention in CADOImpDataSource, which load data when "hit bottom". The defect is the vertical scrollbar cannot indicate the real count of rows and cannot be scroll down to any where immediately.
 
Any way to do this?
 
ice on my way

AnswerRe: How to use a dynamical data source with a known row counteditorTim Deveaux27 Oct '09 - 8:12 
Hi
 
No, that shouldn't be the case - if you implement GetNumCols and GetNumRows in your datasource, then
 
	int index = AddDataSource(&m_data);
	SetDefDataSource(index);
	SetGridUsingDataSource(index);
should be all you need to get going (alternatively, you can bypass SetGridUsingDataSource and set the cols and rows yourself - they needn't be the same as the data).
 
When the grid needs to paint a cell, it will call your datasources GetCell, which will fill in what's needed, much like you were doing in OnGetCell. The only load time should be in preparing the underlying memory DB, which should be managed by the datasource. If preloading the whole mem DB is a problem, you could probably load as you go, keeping track of how many rows are loaded - my thought is if you know the row count you've already loaded everything. Either way, this is different from the OnHitBottom approach.
 
It's a nice advantage to have a datasource that knows it's dimensions - no need for OnHitBottom, and the scrollbars should be ok.
 
Tim
GeneralCursors: clientside / serversidemembermssg13 Feb '09 - 2:27 
I'm starting to use Ultimate Grid in an application that uses MS SQL-Server 2000 for the database.
I'm using the ADOImpDatasource class supplied with UG and found that I always got empty grids, no matter what SQL statement I employed. The same SQL statements yield data as expected when I retrieve them with my homemade ADO wrapper class used in calculation routines.
I found out that what made the difference was that my homemade wrapper uses client-side cursors (adUseClient), whereas ADOImpDataSource doesn't specify the cursor location which then defaults to server-side (adUseServer).
I inserted one line into the source of ADOImpDataSource that sets the cursor location to adUseClient (pConnection->CursorLocation = adUseClient), and the grids then filled up with data as expected.
 
Am I missing something here?
QuestionUsing .mdf files in Ultimate Grid?membervahid_m_20089 Dec '08 - 23:54 
Hi, Tim
 
How can I using mdf Microsoft SQL Server Database files(in version 2005 )(*.mdf_*.ldf) in my mfc project with Ultimate grid control?
 

Thanks a lot !
AnswerRe: Using .mdf files in Ultimate Grid?editorTim Deveaux10 Dec '08 - 6:15 
You'll need to have MS SQL Server (or Express) installed, then you can set up an ODBC datasource if you have a correct ODBC driver (Control Panel, Administrative Tools, Data Sources(ODBC)).
 
Once that's done, you should be able to use one of the existing grid datasources (ODBC, ADO, OLEDB) to connect to the SQL Server database engine through that driver. For SQL Server 2005, I think you can use the SQL Server driver or the newer SQL Native Client to set up the datasource.
 
Tim
GeneralRe: Using .mdf files in Ultimate Grid?membervahid_m_200815 Dec '08 - 23:48 
Hi Tim
 
Ok,I found it,but I want a connect string like "Driver={SQL Native Client};Server=.\SQLExpress;AttachDbFilename=c:\asd\qwe\mydbfile.mdf; Database=dbname;Trusted_Connection=Yes;"
with this connect string like a access *.mdb file I can put my *.mdf & *.mdl file side of my project and run it.
Cleary same as your sample ADO datasource that put "test1.mdb" side of program I want use a file like "test1.mdf";
GeneralRe: Using .mdf files in Ultimate Grid?editorTim Deveaux17 Dec '08 - 6:20 
I think the .NET SqlClient can support (e.g. build a connection string) with this type of file spec, but not ODBC.
 
Tim
GeneralProblem with the Datasource based on SQL Server2000memberjiangbing30 Nov '08 - 1:46 
Hi, Tim
Use the CUGODBCDatasource and UGctl to connect SQL Server2000.
When the field type is smalldatetime(fold:Ultimate Grid\Examples\ODBCEx), the programmer crash. Why...!
Thanks a lot!
GeneralRe: Problem with the Datasource based on SQL Server2000editorTim Deveaux30 Nov '08 - 7:48 
Which version of Visual C++ are you using?
 
Tim
GeneralRe: Problem with the Datasource based on SQL Server2000memberjiangbing30 Nov '08 - 15:07 
I use the VC6.0. Is it the key?
GeneralRe: Problem with the Datasource based on SQL Server2000editorTim Deveaux2 Dec '08 - 9:24 
Hi
 
My SQL platform is a bit limited here - I was able to open a table with a smalldatetime (I don't see smalltime) though, with the example you mentioned. This code in CUGRecordset::BindFields should execute:
 
		// date and time.  CString limited, as is OLEDate variant.
		// Though there are DATE_ and TIME_STRUCTs, RFX_DATE uses
		// TIMESTAMP_STRUCT so all these mapped to same...
		case SQL_DATE: 
		case SQL_TIME:
		case SQL_TIMESTAMP:
			cfi->pValue = (void *) new TIMESTAMP_STRUCT;
			memset(cfi->pValue, 0, sizeof(TIMESTAMP_STRUCT));
			break;
		break;
 
There were a couple of changes to this method in Update 02 - and a previous version would ASSERT(0) if the field type was not identified - but not sure how this would affect you.
 
What type of crash occurs - and does it occur binding to the field, or at some other point?
 
Tim
GeneralRe: Problem with the Datasource based on SQL Server2000memberjiangbing4 Dec '08 - 3:18 
Hi Tim,
Thanks a lot for your reply! yes ,it is "smalldatetime" type field.
I find that there is no problem with the release version program.
 
The debug version crash with the following information:
 
Debug Assertion Failed!
Program:... imateGrid\source\Ultimate Grid\Examples\ODBCEx\Debug\Ex11.exe
File:olevar.cpp
Line:2251
 
For information on how your program can cause an assertion failure, see the 
 
Visual C++ documentation on asserts.
(Press Retry to debug the application)

GeneralRe: Problem with the Datasource based on SQL Server2000editorTim Deveaux4 Dec '08 - 6:40 
Hi
 
I don't see the problem in debug builds, compiling both against the standard VC6 directories and the PSDK 2003. Line 2251 of olevar.cpp doesn't show me anything. Are you using another version of the Platform SDK?
 
Try to debug the assertion (Retry) and see what the code says - you might also want to open the call stack window to track the call(s) back to the example code.
 
Tim
QuestionDatasource based on Oracle OCImembermgampi29 Aug '07 - 1:32 
Hi;
has anyone ever created a CUGDataSource based on Oracle's OCI API?
Any help in this is very welcome...
 
Martin
AnswerRe: Datasource based on Oracle OCImemberpengdingfu26 Nov '07 - 17:05 
I think this site will help you:
http://www.codeguru.com/cpp/data/mfc_database/oracle/article.php/c1165/
 
================================================
Dingfu Peng , from china
my msn : pengdingfu###hotmail###com

Mad | :mad:

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130523.1 | Last Updated 25 Aug 2007
Article Copyright 2007 by The Ultimate Toolbox
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid