Contents

We've placed some answers here to a few of the most common questions folks have asked about when using various aspects of the Ultimate Grid. This page will probably grow as more people use the grid in different ways.

If you've come across an issue with the Ultimate Grid that needed a work-around or a bit of documentation that didn't quite explain all the ins and outs of a particular function call, please feel free to submit it for inclusion — you can be pretty sure it will be of help to someone else out there!

We've also included a small group of samples which are not part of the main sample projects download — these should form a FAQ directory in the Ultimate Grid directory when unzipped to the same location as the main downloads.

Q: In my application I need to perform a specific action when the grid loses focus, but the OnKillFocus notification is not always called. What can I do to correct this?

A: The Ultimate Grid will send the OnKillFocus notification every time it loses focus. This includes when a user starts to edit or shows a drop list. This means that if your grid does not have a drop list cell type and the user is not allowed to edit, it is safe to use the OnKillFocus notification and be sure that it will work.

But what if the user needs to edit cells? We've written a simple example that demonstrates the additions required to both the edit control and the drop list cell type in order for this to work properly.

See the sample project in the Faq\Focus Grid project included in the GridFaq_samples download.

Q: When opening a database created with Access 2000 through MFC DAO classes in Visual C++, you get the following error message: Unrecognized database format.

A: With the release of MS Access 2000 Microsoft has updated DAO to version 3.6, changes in the new version were very minor but big enough to prevent DAO 3.5 to open new files. In order to open the new files in MFC application we need to sync the current version of MFC - like so:

Q: When a user is in edit mode and hits the TAB key, I need to finish editing and move to another cell.

A: This type of functionality can be achieved through use of the OnEditContinue notification — returning FALSE from this notification prevents the grid from automatically activating the edit on the cell moved to:

Q: When the user selects an item from a drop list cell, how can I examine the selected entry for validation?

A: You can easily get the text of an item selected by the user. The droplist celltype will send a message to the OnCellTypeNotify notification indicating that the user has selected an item. At this point the param passed in will point to a CString which contains the selected text. The following code demonstrates how you can do this:

Q: I am using DAO datasource and I seem to be getting a rather useless result from GetNumberRows(). When I call this function it tells me how many rows are visible on the screen rather than how many are in the grid. For example, a typical population would be twenty rows but it reports back the six that can be seen.

A: Yes - you are getting the rows that the grid knows about so far. If your tables are small, you can call the GetNumRowsComplete method in the datasource class - if you do, you should probably SetNumberRows to this value. Typically done after you open.

Q: I am using DAO datasource and I'm having trouble changing the state of cells after population. I can set the ReadOnly state using SetColumnDefault but if I try and set the state of individual cells later using GetCell, SetReadOnly, SetCell it doesn't make any difference to it. I've tried using a RedrawAll after setting all the ReadOnly states I want but they still have no effect.

A: No, SetCell when used with a datasource will typically not be able to store properties like color, readonly, etc. Here we use OnGetCell to modify things as they are coming from the datasource.

For example, you would have to keep track of what cells are to be made editable then check in OnGetCell whether that flag should be set.

If you're going to have to track this type of thing on a per cell basis, it might be best to default to read/write then do the checking in OnEditStart, where you can cancel the edit.

Q: Whenever I call CUGCtrl::SetGridUsingDataSource() (actually when AdjustComponents() is called), the grid control takes the focus to itself. This interrupts our application's normal behavior. How can I get around this?

A: This problem can be solved by preventing the grid from updating itself.

This can be easily done by calling EnableWindow(FALSE) on the grid. The following logic will do the trick:

Q: I am modifying a Client/Server (TCP/IP Internet) application to use the grid to display data. Our data sets are quite large so I only want to send a small subset of the data at a time for viewing to the Client (versus sending the entire data set). But, I still want the scroll bar to represent the entire data set on the server, instead of just what has been loaded into the grid. What would be the best way of doing this?

A: The scroll bar computes its relative size according to the number of rows CUGCtrl thinks it has. This is not directly coupled with the number of rows in the datasource.

You can tell the grid it has 10,000 rows while connected to a datasource with 50 rows, as long as there are guards in place to deal with out of range calls to GetCell in the datasource. (Which, in your case, will probably mean querying the server for a new range of records).

The best thing to do here here would be to derive a custom datasource to use with the grid and allow that to be your interface with the data on the server. The datasource will provide a good place to encapsulate the buffering you want for records.

Q: I want to move selected cells with drag-and-drop functionality build into the Ultimate Grid. I have tried to return 'DROPEFFECT_MOVE' from 'OnDragDrop' notification, but it does not seem to be working. Am I doing something wrong?

A: As it turns out the solution to the problem is quite simple and it does not require any modifications to the source code. To get the 'move' effect to work, all we have to do is clear data in selected cells. We have a chance to do this just before data is copied into the new location.

Q: I have looked through the grid but I haven't found a MoveRow() function. I need to move a row/record in my grid to a new location, how do I do it?

A: One thing you could try is the following — note that it will only copy the text that is contained in the cells, it won't copy other cell properties:

CMyGrid::MoveRow( long lSourceRow, long lDestinationRow )
{
// turn drawing off ( so the grid will not redraw itself as we perform
// all of the sub functions )
EnableUpdate( FALSE );
// turn multiselection on, if it's not already
SetMultiSelectMode( TRUE );
// get all of the information in the source row and then delete the row
SelectRange( 0, lSourceRow, GetNumberCols() - 1, lSourceRow );
CutSelected();
DeleteRow( lSourceRow );
// insert a new row at the destination and copy the text information
// from the old row into the newly created one
InsertRow( lDestinationRow );
GotoCell( 0, lDestinationRow );
Paste();
// turn drawing back on and issue one RedrawAll() yourself
EnableUpdate( TRUE );
RedrawAll();
}

Q: When I create a modal dialog (DoModal function call) from either an OnLClicked event, a button cell-type, an ellipsis cell-type, etc. The first mouse click on the dialog is captured by the grid not my dialog. What is going on?

A: This problem is caused by the fact that the Ultimate Grid sets capture to mouse events when user presses the mouse button, and releases it when user lets go. However, the mouse notifications are sent while the mouse capture is still active.

To solve our problem we have to release mouse capture just before the dialog becomes active, as in this sample:

Q: I am using a DAO datasource and I am trying to set a color to certain cells red, but I am not able to figure out how this can be done.

A: This problem is caused by the fact that the Ultimate Grid always relies on current datasource to provide it with all of the information about all of its cells. The problem with the DAO datasource (and other datasources that bind to a database) is that it is not able to store any information other than cell's value.

You can easily work around this problem with the use of the OnGetCell notification. This notification is fired just before a cell is painted and can be used to set additional information (like back colors, fonts, cell types, etc.) to a cell. The information set here will not be stored back to the datasource, but it is a perfect place to customize how data is presented to the user.

For example, if you want to change background color of the cell (2,2) then your code might look like this:

Q: Is it possible to use column swapping when my Grid has two top heading rows? When I swap a col (row -1 col 1) and there is a cell over this col (row -2 col 1 and col 2) that is joined with another cell (row -2 col 2). When I now put the cell (row -1 col 1) and move it to to col 5, then the cell (-2 1) is moved also. But over the Cell (-1 2) is nothing (no Cell, before there was the joined cell). Is is possible to change the behavior of the Grid so that the two cols (1, 2) under the joined cell (-2,1 ; -2 ,2) are moved to the new Position?

A: This problem is caused by the fact that the grid ignores all top headings, except for the first, when swapping columns. And because you have the joins in second top heading everything gets mixed up.

To solve this problem you will have to make some simple modifications to the source code.

First you will have to create virtual member functions for both CUGCtrl and you derived grid class. The function should be declared and used as:

Q: If I want to pre-select multiple cells in the code for the users, what function that I can use? There is no SetSelect() in class CUGMultiSelect!

A: The solution to this problem is quite simple, all you have to do is call CUGMultiSelect::StartBlock function from OnSetUp of your CUGCtrl derived class (or any other place that you might want to select cells from):

m_GI->m_multiSelect->StartBlock ( col, row );

The parameters specify the column and row of the cell to be selected, you can call it multiple times if you want more cells to be selected.

Q: I noticed that when I am doing a FitToWindow(), with all my fields represented (0, maxFieldNum) that as I expand, it resizes fine, but when I shrink it, the last field does not get resized and therefore everything else shrinks in proportion. So if you go back and forth getting larger and smaller, eventually everything else disappears except the last column.

A: This problem is caused by the fact that the column width is stored as an integer value.

The following is code for a FitToWindow function that has been added to a CUGCtrl derived class (MyCug). As you can see this function is not using the current col width but a value stored in the array of integers (of original values). This way the fit to window calculation will always use the same values and will not be affected by the previously sized window:

Q: When I am editing a cell in the Ultimate Grid, and I right-mouse click, a menu pops up that has the options 'Undo/Cut/Copy/Paste...'. I do NOT want this to pop up. How can I disable it?

A: Due to the fact that the edit control in the Ultimate Grid is derived from the CEdit class, every function and notification is available for our use.

The notification that allows us to disable or change the Clipboard popup menu in our edit control is:

void CUGMaskedEdit::OnContextMenu(CWnd* pWnd, CPoint point)

Now if we just want to get rid of the default context menu, then we can just leave the function empty (no code). However, if we want to display the same menu as in the grid (in non edit mode) than we will need to implement following code:

Q: I have called StartEdit() from OnLClicked() and as soon as I am done editing it replaces the text I just entered with the stuff that was there before. Help me!

A: OnLClicked() gets called twice by the grid. Once in response to the windows message WM_LBUTTONDOWN and once in response to the windows message WM_LBUTTONUP. When the left mouse button has been depressed, OnLClicked() gets called with updn = 1. When the button is released OnLClicked() gets called with updn = 0. So in OnLClicked(), if you do not check the state of this variable and you call StartEdit(), you will be starting editing twice. The normal procedure is to start editing when the button is released.

Q: I can change the background color of the cells in my grid, but the area not covered by cells in the grid window is always the standard window color or white. How do I change the color of this region?

A: The Ultimate Grid provides a notification where you can change the color to be used in this region. This notification is called OnGetDefBackColor(). If you do not override this notification in your own derived grid class, the base class (CUGCtrl) will always return the standard windows color based on your system colors. Return a COLORREF for the color you want this region to be painted with:

Q: When I start editing a cell of the grid, the edit control becomes really big (larger than the underlying cell), and as I type it continues to get bigger and bigger. What is going on?

A: The default edit control that comes with the Ultimate Grid (derived from the class CUGEdit) contains the ability to automatically resize itself in response to the user's input. It also has the ability to size itself to fit the initial font that is in the cell that is being currently edited. This auto size capability can be turned off at your discretion:

( ( CUGEdit* )GetEditClass() )->SetAutoSize( FALSE );

You would probably want to do this globally for your entire grid based app and would do it from OnSetup().

Q: The data in one of my columns is numbers, but when I go and sort it, the grid sorts it as text. How do I get the grid to sort it as numeric data?

A: When it comes time to sort the contents of a column, the grid will call the notification OnSortEvaluate() and pass in the two cell objects it is currently trying to sort. The default implementation of OnSortEvaluate() checks the datatype of the objects involved and sorts them appropriately. You can ensure that your numeric data is sorted as numeric data and not as string if you set the cell data type of the cells in that column to numeric data.

One problem you could encounter is if your data is being entered/modified by the user from keyboard entry. As soon as editing finishes taking place on a cell, the text the user entered into the edit control is copied back to the cell of the grid by calling QuickSetText(). Now by default QuickSetText() not only changes the text in the cell specified but also sets the cell datatype of that cell to UGCELLDATA_STRING. But we want the data to be numeric or it won't sort properly — to ensure that the data of our numeric column is numeric data (even after the user has edited it), we would do something like this:

Q: I have written a routine that goes through and appends a bunch of rows, adds bitmaps to cells, resets the width and height of all components in my grid and changes all of the background colors to a pink & green checkerboard, every time I call this function the grid flickers up a storm as it repaints itself in response to all of these changes. How do I stop the grid from painting itself?

A: There are two different functions you can use to turn off the grid's internal ability to repaint itself:

EnableUpdate( FALSE );
//or
SetPaintMode( FALSE );

To turn on the ability to redraw you would call the same function again, this time with the parameter = TRUE. After calling this function, the grid will not repaint itself at all, and manual calls to RedrawAll() will also cease to function.

Q: I created a font and set it as the default font of the grid using SetDefFont(), but I do not see my font being used. What is going on?

A: The most likely reason is that the font is going out of scope before the grid can use it to draw the text in the cells. When you create a GDI object for use with the Ultimate Grid, you should make that object a member of your derived grid class. Then it will always be available to the grid. In your destructor for your grid class, you'll destroy the object.

Q: How come when I set a mask to a cell using QuickSetMask() or CUGCell::SetMask() and then go and edit the cell, the mask does not do anything?

A: The most likely reason is the you are not using the Ultimate Grid masked edit control. The masked edit control (CUGMaskedEdit) is a separate class from the Ultimate Grid's standard edit control (CUGEdit). You can find a copy of the masked edit control in your \addons directory. Using the masked edit control is a simple process. First create an instance of CUGMaskedEdit and make it a member of your derived grid calls (MyCug for example). Creation of the masked edit control is a two stage process, after the constructor, you should call Create() on the control (again here from OnSetup()):

In the above example, we only want to use the masked edit control in the fifth column of our grid, otherwise we will use the standard masked edit control. If we wanted this edit to be the default for all cells, we could call SetNewEditClass().

Q: I have put the Ultimate Grid into an MFC extension .DLL and it does not work properly or blows up on me in certain places. What gives?

A: If you use the AFX_EXT_CLASS macro to export the classes you need from the Ultimate Grid, everything should work fine. One thing that should be noted, the Ultimate Grid souce code will conditionally compile in code if OLE has been enabled (you have included afxole.h in your project). When an MFC extension .DLL is created, the standard stdafx.h has afxole.h included so all of the code (drag and drop stuff) that needs OLE present will be compiled into the .DLL. When you go and create a project that uses the MFC extension .DLL you will also have to include afxole.h in your stdafx.h header or the code will not match up and you will encounter serious problems.

Q: I am using a datasource (DAO, ODBC, custom) and I have called all sorts of QuickSet... functions to change things in the cells of my grid and I do not see these changes. What did I do wrong?

A: When you use an external datasource, the Ultimate Grid expects all of the data it needs for the cells to be coming from that datasource. If there are certain things that are not specified in the datasource that you want to display in the grid (fonts, joined cells, colors, etc), you have to set them manually yourself from OnGetCell(). OnGetCell() is called in response to either yourself or the grid (internally) calling GetCellIndirect(). When it comes time to paint the cells of the grid in the current window, the grid internally does a GetCellIndirect() to get the information it needs to paint each of those cells. Even if there is no information in the datasource for the cells we want to modify, or we want to change that default information, we are given a chance in OnGetCell() to intercept the data before it gets displayed.

The above code will fill all the cells of the grid (not the headers) with a multiplication table, irrelevant of what the datasource is holding (e.g. a DAO table).

Since OnGetCell() already provides a pointer to the cell object, we don't need to do a GetCell() call (in fact doing so could lead to infinite recursive calls!). Likewise you should be wary of using QuickSet... members from OnGetCell(). As OnGetCell() gets called a lot, it is not a good idea to put a lot of code here and one should never put a loop of any sort in OnGetCell(), or you will take a huge performance hit.

A: For this we will have to add new notification to the droplist box that will give us the index. Since the drop list box used in the grid is derived from MFC's List box it is easy to get the extended functionality.

First we will have to define a constant for the new notification that we are going to create. You can do this in the header file for the DropList class:

#define UGCT_DROPLISTSELECTEX 102

Now, lets find the CUGLstBox::Select function. Here we are actually going to pass the index value to the OnCellTypeNotify:

Q: Is there a member function to delete (clear) all the rows, except the headers, in the Ultimate Grid control?

A: No. You can either iterate through a for loop and call DeleteRow() to delete all of the rows or in one go, you can do the following:

SetNumberCols(0);
SetNumberRows(0);
GetDataSource(0)->Empty();

(this assumes you're not bound to a database, you're just using the grid's memory manager). The only drawback to this method is that it will get rid of everything (including the headings and all setup information you've applied to the grid).

Use the above, but first create some sort of GridSetup() function. There set up the number of column, rows, the headings information, global parameters (like SetHighlightRow(), SetMultiSelectMode(), SetVScrollMode(), EnabelCellOverLap(), etc). Then when you delete everything, you can quickly get everything set up again when you call your GridSetup() function

Q: In my application I need to present users with a popup menu that contains sub menus, how can I do this?

A: The Ultimate Grid allows you to get pointer to its popup menu. You can then use that CMenu object to create complex menus. The following code sample demonstrates how you can create sub-menu options:

This sample uses the OnMenuStart notification to add the menu options, which shows the potential for flexible menus. However, if in your application grid will have the same popup menu at all times you can setup the menu from OnSetup.

Q: I am having problems tabbing between dialog items when the grid is on the dialog, I am not able to tab out of the grid.

A: The grid control has been designed in such a way to capture all input keys, this was done to provide maximum flexibility to our users. To accomplish this we have handled the OnGetDlgCode message in the CUGGrid class and returned DLGC_WANTALLKEYS.

The easiest way to correct this situation and allow your users to tab in and out of the grid (without modifications to our source code) is with the use of the OnKeyDown notification in your CUGCtrl derived class. Like so:

Share

About the Author

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.

Comments and Discussions

Does this handle (or force) the user to pick something off the list, as opposed to typing in an arbitrary string? My initial test indicate "yes", since passing that key to the list forces the list to activate.

This depends on how you start the edit - with a 'hot' droplist, if you call StartEdit in OnCharDown in your grid ctrl, yes, the droplist will appear briefly and be usurped by the edit - the grid ctrl OnCharDown will be called after the celltype's OnKeyDown.

If you start in an lclick, it should be ok.

So, the 'normal' droplist would work better with full keyboard control.

Not sure precisely what you're looking for here, I guess.

The Demos dir is included with the samples download - the CellTypes demo is worth a look.

I've been developing with Ultimate Grid & Toolbox for about 4 years, and through 3 versions. Our product uses both quite extensively. Is there a good place to review all the forum posts that are related to the products?

It seems to me that people are just posting questions and comments to the end of individual articles, is there a Forum specifically for the Ultimate stuff? I'd like to keep informed with updates to the products (found bugs, etc).

thanks for reply.What I want to do is: The first column has 8 DropLists. The next column contains also 8 DropLists. The 3rd column contains 8 checkboxes. Therefore one row has 2 DropLists and one CheckBox. Depending on what is selected in one of the left DropList, I want to display the other DropList or the CheckBox in the desired row. So I only want to hide/show the "control" of one cell.

If I change the cell type for one of the cell I will loose all information of this cell, what means that if I want to hide a droplist by removing it, I have to uses a lot of member variables which store the contents and current selection of all the "Show/Hide"-cells. Is there no easier way to hide a DropList or CheckBox?

You can change the way the cell is displayed in your OnGetCell override.

Briefly, this notification is called after the cell data has been retrieved but before it is displayed, allowing you to change the celltype, text, etc. temporarily for display. You won't alter the underlying cell data in storage.

OnGetCell will not recurse if you call GetCell within OnGetCell, so you can examine the neighboring cells to decide what to display from within the OnGetCell notification.

When the UGCT_DROPLISTSELECT notification is received, set a flag to indicate which column contains the controlling droplist cell for that row, and call RedrawRow to effect the changes via OnGetCell.

You might consider using the param member of the sideheading cell (SetParam/GetParam) of each row to store this flag if you want to minimize extra vars - I'm assuming that the controlling droplist for one row might be in col 0 while in another row might be col 1 etc.

Note that this doesn't 'remove' cells from the grid, just changes their celltype, text etc on the fly - if you want to hide columns entirely, set the column with to 0 and vector the OnCanSizeCol notification.

If you want to selectively exchange a droplist cell for a checkbox cell in the same column (e.g. only two columns showing at one time), I think you could also do this in OnGetCell by selectively swapping cell pointers.

Remember that there can be more rows/cols in the underlying datasource than there are in the grid, which can come in handy.

first, thanks for the excellent control, this is just what I need.my question is that when selecting cells with mouse, the CPU usage is high for me, so I changed the code in CUGGrid::OnMouseMove a little (and maybe huge), the changes is as follows:1. add two static variable for row and col static int m_col; static long m_row; if(col == m_col && row == m_row) return; 2. delete the "while(1)"3. and other minor changes.with these changes, the CPU usage is ok for me.

Q1: I am not very good at programming, so can you kindly tell me why you put "while(1)" in the CUGGrid::OnMouseMove? Q2: Can I change your code and use it in my project(non commercial software but used as a tool in my company)?thanks in advance.

Q1: can you kindly tell me why you put "while(1)" in the CUGGrid::OnMouseMove?

That's a good question - it would be interesting to see your rewrite and do some testing - I think the message pump might be the actual cycle thief in there, but would need to test.

lazymiken wrote:

Q2: Can I change your code and use it in my project(non commercial software but used as a tool in my company)?thanks in advance.

The CPOL[^] is pretty clear on this point - I'd think that's perfectly ok from my reading of things, but I can't say that because if I do legal people will wag their fingers at me - the CPOL is the document to examine.

Cheers and thanks - if you'd like to post that code block we should get some more feedback.

That's a good question - it would be interesting to see your rewrite and do some testing - I think the message pump might be the actual cycle thief in there, but would need to test.

yes, I deleted the message pump also, as I said before I am not a professional programmer and don't have too much time for testing, I don't quite know the consequence of all the changes I made, but by now, everything seems ok.

Tim Deveaux wrote:

Cheers and thanks - if you'd like to post that code block we should get some more feedback.

I did nothing new or innovating to the original code, what I really did is just as the following:1. add two static variables to remember the row and col.2. delete the "while(1)"3. delete the message pump (remember I said the changes may be huge in the last message).4. I also notice that repaint optimization maybe needed in the CUGSideHdg and CUGTopHdg, but I am not sure.there is really nothing new here, to your guys, I think the above information is enough, no need to post my code.

I took out the while(1) and message pump code and tested a few samples, and didn't see any problems. I did notice that the CPU usage was better.

I'm not sure why this code is the way it is. It could be it was written this way to optimize movement operations - an optimization that might not be noticable on a modern machine, but possibly a concern on a typical mid 90's processor.

for example, i execute my program using this gridand i execute another program (anything ok).if another program size is smaller than my program's grid, and another program is placed on grid.then grid cant be redraw when i clicked my program under the another program.if i close another program, then grid redraw good(just when i click my program, then not redraw)

though i call redraw again, it dont redraw grid.just grey rectangle. do you know?

can we make header control flexible in such a way that vertical grid lines become optional i.e some of rows have vertical boundary between two columns and some does not.if there is any way please tell me

Thanks for replying tim , That was a nice option, but what if i want to make such a grid that no of columns depend on users choice i.e if user want one column for first row ,two for next two rows ,and then again a single coloumn for next row

can we make our grid this much flexible using functionalities of header contol?

I am working on a program using the MFC Doc/View architecture. I have one document type with multiple views. 2 of the views use ultimate grids. When the document class calls "UpdateAllViews()", the grids are updated but the scroll bars in the grids are not redrawn - they are left blank. If I alt-tab away and back, the scroll bars are then drawn correctly.

Tricky - haven't debugged into this, but suspect that the issue might lie with the code in CUGHScroll::Moved() and CUGVScroll::Moved() methods, which might just be letting things go if the position hasn't changed.

There might be a missing call to Invalidate here - you could experiment (er, yes, so could I but am pressed for time units today).

"UpdateAllViews()" does invalidate all the views. I’ve added an override of the CView member function “OnUpdate” where I call the grid’s "RedrawAll()" function and the problem is solved. Thanks for your help!

I need to setup a grid cell so it will display data the same way the COXCurrencyEdit control does.UGCELLDATA_CURRENCY does formating but it uses the number format. When I insert data within one dialog using COXCurrencyEdit control I can show to a user values like: $100.50. Then I do retreive the value and store it in database. Later on I want to display that value in a grid. It should be in the same format as in edit control. But UGCELLDATA_CURRENCY uses different formating rules (number format to be specified ex: 100,00, different separator, no currency symbol).

So, in OnGetCell, if the UGCELLDATA_CURRENCY property is set, call cell->GetNumber on the cell then use, say, CString.Format to format things to your liking and call cell.SetText with that. That will set the text to be displayed 'on the fly' - OnGetCell is called after the cell has been filled in by the underlying datasource, but before the cell text is drawn in the grid.

If str.Format(_T("$%.2f"), number); still gives you the wrong separator, it's being picked up by the regional settings - you might need some further tweaks.

I hope the gid/data source classes have a method/mechanism like CWnd::Invalidate()or CDialog::UpdateData(bool), which can update the information back and force between the grid and the data source under the hood, automatically.

Your question has different answers depending on the type of data source.

If, for example, your grid was using a custom datasource based on an array of integers, and you changed the values in the array independently of the grid, then yes, calling Invalidate() (or RedrawAll()) will reflect the changes as the grid will call the GetCell() override to get the data needed for display.

In a simple array based datasource such as this, calls to SetCell() or the results of a user edit would normally be written directly to the array without a need for a call to UpdateData(). If you wanted to introduce a buffered write you would need to code it in your datasource class.

For other types of database provider based datasources, edits can be direct or transactional. A refresh might require re-querying depending on the nature of the dynaset and/or provider.

Other than NoteType Cells that don't support right to left languages and don't track mouse pointer and don't adjust themselves to be drawn inside of the boundaries of the grid, is there any other way of adding tooltips to cells?

By the way thanks for sharing and supporting us for free

-- modified at 21:47 Friday 5th October, 2007

// "Life is very short and is very fragile also." Yanniwhile (I'm_alive){ cout<<"I love programming.";}