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.