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

The Ultimate Grid FAQ

, 5 Oct 2007
Rate this:
Please Sign up or sign in to vote.
A selection of frequently asked questions submitted by users of the Ultimate Grid

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

Contents

Introduction

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.

Frequently Asked Questions

Why is the OnKillFocus notification not fired reliably? (11/23/2005)

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.

How can I use Access 2000 databases with the grid? (02/11/2003)

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:

#ifdef _AFXDLL
    AfxGetModuleState()->m_dwVersion = 0x0601;
#else
    AfxGetStaticModuleState()->m_dwVersion = 0x0601;
#endif

It is best to use this code when the app is initialized. For more information please see article Q236991 in the MSDN.

Can I exit edit mode when a user moves to new cell with TAB? (09/19/2000)

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:

int MyCug::OnEditContinue(int oldcol,long oldrow,int* newcol,long* newrow)
 {
   GotoCell( *newcol, *newrow );
 
   return FALSE;
 }

How do I know what a user selected in a droplist cell? (11/21/2000)

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:

int MyCug::OnCellTypeNotify(long ID,int col,long row,long msg,long param)
{
     int retval = TRUE;
     if ( msg == UGCT_DROPLISTSELECT )
     {
          CString *tempStr;
          tempStr = (CString*)param;
          MessageBox( *tempStr );
     }
     return retval;
}

You can also reject the selection by returning FALSE.

Force the widths of the cells in table/side headings to size (08/25/2000)

Q: Is there a simple way to force the widths of the cells in the table heading and side headings to automatically size such that all the headings are visible?

A: Best way to get content of each cell to show fully is by using the BestFit function. This function should be called after the grid window is created.

To get top headings to show up, just set the flag to UG_BESTFIT_TOPHEADINGS, but to get the side header to adjust itself you must use '-1' as your starting column:

    m_grid.BestFit( -1, // Starting col for range calc.

 m_grid.GetNumberCols()-1, // End col


 m_grid.GetNumberRows()-1, // End row

 UG_BESTFIT_TOPHEADINGS );// include top headings flag

When connected to datasource GetNumberRows does not work. (09/19/2000)

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.

Trouble changing cell state using DAO datasource (08/25/2000)

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.

When I call CUGCtrl::SetGridUsingDataSource() grid gets focus (11/21/2000)

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:

  • Disable grid window updates (EnableUpate(FALSE) / EnableWindow(FALSE))
  • Do some data operations (make sure that you do not call Redraw...)
  • Enable updates
  • Redraw All on the grid.

I'm using a droplist and I want to fill the list dynamically (11/21/2000)

Q: I'm using a droplist and I want to fill the list dynamically. I handle the UGCT_DROPLISTSTART message in which I set the list, but this code does not work:

     GetCell(col,row,&cell);

     cell.SetLabelText(DropList);
     SetCell(col,row,&cell);

When I do this, however, the list is only changed the second time when I click.

A: The CUGDropListType provides you with a pointer to CStringList, which stores a list of items to be displayed by the droplist. This is done through param passed into the OnCellTypeNotify.

Knowing that, all you have to do is typecast the paramto a CStringList* and you are free to make any change to the drop list items. The following code shows a simple example of this:

int MyCug::OnCellTypeNotify(long ID,int col,long row,long msg,long param)
 {
    CStringList *list;
    list = (CStringList*)param;

    if ( msg == UGCT_DROPLISTSTART )
    {
        list->AddTail( "My Element1" );

        list->AddTail( "My Element2" );
        list->AddTail( "My Element3" );
        list->AddTail( "My Element4" );

    }
}

Modifying Client/Server (TCP/IP Internet) to use the grid (08/25/2000)

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.

Move selected cells with drag-and-drop functionality (08/25/2000)

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.

This sample code shows the technique:

DROPEFFECT MyCug::OnDragDrop(COleDataObject* pDataObject,int col,long row)
{
 TRACE ( "OnDragDrop\n" );

 // clear selected cells

 int sCol;

 long sRow;
 CUGCell cell;
 GetCell ( 0, 0, &cell );
 m_GI->m_multiSelect->EnumFirstSelected( &sCol, &sRow );
 do
 {

 cell.ClearAll();
 SetCell ( sCol, sRow, &cell );
 }
 while ( m_GI->m_multiSelect->EnumNextSelected( 
    &sCol, &sRow ) == UG_SUCCESS );

 return DROPEFFECT_COPY;
}

When scrolling I want to keep the focus rect always in view. (09/27/2000)

Q: When scrolling with scroll bars I want to keep the focus rect always in view, but I don't seem to get any notifications to inform me that the view was moved. What do I do?

A: The easiest way to solve this problem is by mapping the WM_SCROLL message to your derived CUGCtrl class and implementing the following function:

void CMyCug::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
    // determine how many rows from top row to current row (nOffset)

    long nOffset = GetCurrentRow() - GetTopRow();

    // scroll

    CUGCtrl::OnVScroll( nSBCode, nPos, pScrollBar );

    // set new current row at nOffset from the top

    long yRow = GetCurrentRow();
    long yTop = GetTopRow();

    if ( yRow < yTop || yRow>= GetBottomRow() )
        GotoRow( yTop + nOffset );
}

I need to move a row/record in my grid to a new location (08/28/2000)

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();
}

First mouse click on the dialog is captured by the grid. (05/22/2002)

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:

void MyCug::OnLClicked( int col, long row, int updn, RECT *rect, POINT *point,
    int processed )
{
    if( !updn )
    {
         CMyDialog m_dialog;
         ReleaseCapture ();    // let go of the mouse capture

         m_dialog.DoModal ();
    }
}

I cannot figure out how to set the cell's color when using a DAO Datasource. (12/04/2001)

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:

void MyCug::OnGetCell(int col,long row,CUGCell *cell)
{
    if ( col == 2 && row == 2 )
         cell->SetBackColor ( RGB (0,255,0));
}

Note that at this point the datasource's GetCell method has already been called, so OnGetCell can be used for conditionals (like red text for negative values).

Can I use the column swapping when my Grid has two top heading rows? (08/28/2000)

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:

virtual BOOL OnColSwapped ( int startCol, int endCol );

BOOL UGCtrl::OnColSwapped(int startCol, int endCol)
{
    return TRUE;
}

BOOL MyCug::OnColSwapped(int startCol, int endCol)=
{
    TRACE ( "OnColSwapped\n" );
    // here you have to re-join cells in the top heading

    JoinCells ( 0, -2, GetNumberCols () -1, -2 );
    return TRUE;
}

And finally we activate the notification that we have created:

void CUGTopHdg::OnLButtonUp(UINT nFlags, CPoint point)
{
    .... ... ...
        if(m_ctrl->OnCanColSwap(m_swapStartCol,end) != FALSE)
        {
            m_ctrl->MoveColPosition(m_swapStartCol,m_swapEndCol,TRUE);
            // add the following line


            m_ctrl->OnColSwapped ( m_swapStartCol, m_swapEndCol );
            .... ... ...

I want to pre-select multiple cells in the code for the user (08/28/2000)

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.

Resizing problem when I am doing a FitToWindow() (10/31/2000)

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:

// declaration of a member array m_originalCols:

CArray m_originalCols;
int MyCug::FitToWindow(int startCol, int endCol)
{
    RECT rect;
    int screenwidth, columnwidths, loop, newwidth;
    float ratio;

    //validation checking

    if(startCol <= m_GI->m_numberCols)
        return 1;

    //get the grid screen width

    m_CUGGrid->GetClientRect(&rect);
    screenwidth = rect.right;

    //get the total column widths

    columnwidths = 0;
    for( loop = startCol; loop <= endCol; loop++ )
    {
        columnwidths += m_originalCols[loop];
    }

    //get the ratio

    ratio = ( (float)screenwidth ) / ( (float)columnwidths );

    //reset the column widths

    for( loop = startCol; loop < endCol; loop++) {
        newwidth = (int)( (float)m_originalCols[loop] * ratio );
        SetColWidth( loop,newwidth );
        screenwidth -= newwidth;
    }
    SetColWidth( endCol, screenwidth );

    Update();
    return UG_SUCCESS;
}
int MyCug::StoreOriginalCols()
{
    m_originalCols.SetSize ( GetNumberCols (), 0 );

    for ( int col = 0; col < GetNumberCols(); col ++ )
    {
        m_originalCols.SetAt ( col, GetColWidth( col ));
    }

    return UG_SUCCESS;
}

Disabling the pop up menu. (08/28/2000)

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:

void CUGMaskedEdit::OnContextMenu(CWnd* pWnd, CPoint point)
{
    CMenu *tempMenu = m_ctrl->GetPopupMenu ();
    tempMenu->TrackPopupMenu( TPM_LEFTALIGN, point.x, point.y, pWnd );
}

Called StartEdit() from OnLClicked() and have text problem. (08/28/2000)

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.

void CRandoGrid::OnLClicked( int col, long row, int updn, RECT* rect, 
    POINT* point, int processed )
{
    if( !updn )
        StartEdit();
}

Change the color of the area not covered by cells. (08/28/2000)

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:

COLORREF CTestGrid::OnGetDefBackColor( int nSection )
{
    if( m_bGridHasFocus == TRUE )
        //white backgroud

        return RGB( 255, 255, 255 );
    else //system color for buttons

        return GetSysColor( COLOR_BTNFACE );
}

Edit control continues to get bigger and bigger. (08/28/2000)

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().

How do I get the grid to sort it as numeric data? (08/28/2000)

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.

CUGCell cell;

// mark the fifth column as numeric data

GetColDefault( 4, &cell );
cell.SetDataType( UGCELLDATA_NUMBER );

SetColDefault( 4, &cell );

You would most likely do the above from OnSetup(). Once done, OnSortEvaluate will sort the data appropriately:

int CTestGrid::OnSortEvaluate( CUGCell* cell1, CUGCell* cell2, int flags )
{
    if( flags & UG_SORT_DESCENDING )
    {
        CUGCell *ptr = cell1;
        cell1 = cell2;
        cell2 = ptr;
    }
    switch(cell1->GetDataType())
    {
    case UGCELLDATA_STRING:

        if( NULL == cell1->GetText( ) && NULL == cell2->GetText( ) )
            return 0;
        if( NULL == cell1->GetText( ) )
            return 1;
        if( NULL == cell2->GetText( ) )
            return -1;

        return _tcscmp( cell1->GetText( ), cell2->GetText( ));
    case UGCELLDATA_NUMBER:
    case UGCELLDATA_BOOL:
    case UGCELLDATA_CURRENCY:
        double n1 = cell1->GetNumber( );
        double n2 = cell2->GetNumber( );
        if( n1 < n2 )
            return -1;
        if( n1 > n2 )
            return 1;
        return 0;
    }
    if( NULL == cell1->GetText( ) )
        return 1;

    if( NULL == cell2->GetText( ) )
        return -1;
    return _tcscmp( cell1->GetText( ), cell2->GetText( ) );
}

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:

void CTestGrid::OnSetCell( int col, long row, CUGCell* cell )
{
    if( col == 4 )
        cell->SetDataType( UGCELLDATA_NUMBER );
}

How do I stop the grid from painting itself? (08/28/2000)

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.

I do not want the top or side headings to show up. (08/28/2000)

Q: I do not want one or both of the headings to show up (top or side heading). How do I get rid of them?

A: To hide one of the headings you simply set it's width or height to 0 (zero). For the top headings it would be like this:

 SetTH_Height( 0 );

For the side heading it would be like this:

 SetSH_Width( 0 );

You would probably call either of these from OnSetup() of your grid class.

NOTE: If either the side heading or top heading is not present (has a width or height of zero), then the corner button will not displayed.

I set the default font of the grid but don't see it. (08/28/2000)

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.

void CTestGrid::OnSetup()
{
    CDC * pDC;

    pDC = GetDC();
    nHeight = -MulDiv( 10, GetDeviceCaps( pDC->m_hDC, LOGPIXELSY), 72 );

    ReleaseDC( pDC );

    m_font.CreateFont( nHeight, 0, 0, 0, 400, 0, 0, 0, 0, 0,0, 0, 0, _T(
        "Verdana" ) );

    SetDefFont( &m_font );
}

The above code snippet creates a font (which is a member of CTestGrid), scales it to the correct size for the screen and sets it as the default font to be used in the grid.

QuickSetMask() or CUGCell::SetMask() problem (08/28/2000)

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()):

 CRect cRect;
 m_maskedEditCtrl.Create( WS_CHILD | WS_VISIBLE, cRect, this, 13523523 ); 

Now that the control is created we need to tell the grid to use the control when we edit. This can be done from OnEditStart:

int CTestGrid::OnEditStart( int col, long row, CWnd** edit )
{
    if( col == 4 )
        *edit = &m_maskedEditCtrl;
    return TRUE;
}

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().

Ultimate Grid in an MFC extension .DLL problem (08/28/2000)

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.

Using a datasource (DAO, ODBC, custom) problems. (08/28/2000)

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.

void CRandoGrid::OnGetCell( int col, long row, CUGCell* cell )
{
    if( col >= 0 && row >= 0 )
        cell->SetNumber( (col+1) * (row+1) );
}

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.

How do I get the DropList index value of the item selected? (11/23/2000)

Q: How do I get the DropList index value of the item selected?

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:

void CUGLstBox::Select()
 {
    CUGCell cell;
    CString string;
    int col = *m_col; //m_ctrl->GetCurrentCol();


    long row = *m_row; //m_ctrl->GetCurrentRow();


    m_selected = TRUE;

    //get the string selected

    GetText(GetCurSel(),string);

    //------ add this line ---------------

    m_ctrl->OnCellTypeNotify(m_cellTypeId,col,row, UGCT_DROPLISTSELECTEX,
        (long)GetCurSel());
    //------------------

    // ...

And finally in the OnCellTypeNotify override we can handle the notification and display it in a message box:

else if (msg == UGCT_DROPLISTSELECTEX)
{
    string = new CString;
    string->Format ("%d",param);
    MessageBox (*string);
}

I want a fixed number of columns,& hide horz scroll bar (08/28/2000)

Q: For my application, I want a fixed number of columns, and I want to get rid of the horizontal scroll bar. How do I do this?

A: The easiest way to hide the scroll bars is by setting their height/width to 0.

 m_grid.SetHS_Height ( 0 );
 m_grid.SetVS_Width ( 0 );

Is there a member function to delete all the rows in the grid? (08/28/2000)

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

How can I show a complex popup menu in the grid? (09/19/2000)

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:

int MyCug::OnMenuStart(int col,long row,int section)
 {
   EmptyMenu();
   // get pointer to popup menu used by the grid

   CMenu *gridMenu = GetPopupMenu();
   CMenu subMenu;

   if ( section == UG_GRID )
   {

     gridMenu->AppendMenu( 0, 1001, "1st option" );
     gridMenu->AppendMenu( 0, 1002, "2nd option" );
     gridMenu->AppendMenu( MF_SEPARATOR );
     // create first submenu


     subMenu.CreatePopupMenu();
     subMenu.AppendMenu( MF_CHECKED, 1011, "3rd option" );
     subMenu.AppendMenu( 0, 1012, "4th option" );
     subMenu.AppendMenu( MF_GRAYED, 1013, "5th option" );

     gridMenu->AppendMenu( MF_POPUP, (UINT)subMenu.GetSafeHmenu(), 
         "More options" );
   }
   return TRUE;
}

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.

How can I get heading cells from point? (11/21/2000)

Q: I found that the GetCellFromPoint function does not work for heading cells, is there a way can I correct this?

A: By design the GetCellFromPoint function will not work for cells that are on headings.

We've written a customized version of the GetCellFromPoint function to provide this type of functionality, called FindCellFromPoint so there is no confusion.

See the example project in the Faq\GetCellFromPoint directory of the UltimateGridFaq_samples download.

How can I limit number of characters entered by the user? (09/19/2000)

Q: In my application I need to limit number of characters my end users are allowed to type.

A: The easiest way to accomplish this is not through use of mask edit control but through OnEditVerify notification.

For example, to limit user's input to 50 characters you can use following code:

int MyCug::OnEditVerify(int col, long row,CWnd *edit,UINT *vcKey)
{
    // This code can also be enhanced to check for replace selection


    if ( m_editCtrl->GetWindowTextLength() >= 50 )
    {
        // user has hit max limit, discard further input

        return FALSE;
    }
    return TRUE;
}

How can I tab between dialog controls if grid is on dialog? (09/19/2000)

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.

UINT CUGGrid::OnGetDlgCode() 
{
    // TODO: Add your message handler code here and/or call default.

    if ( IsChild( GetFocus()))

        return DLGC_WANTALLKEYS|DLGC_WANTARROWS;
    else
        return CWnd::OnGetDlgCode()|DLGC_WANTARROWS|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:

void MyCug::OnKeyDown(UINT *vcKey,BOOL processed)
{
    // *Note: this notification will not be called when

    //    the grid is in edit mode.

    if ( *vcKey == VK_TAB && GetKeyState( VK_SHIFT ) < 0 )
    {
        // move input focus to the previous dlg item

        ((CDialog*)GetParent())->PrevDlgCtrl();
    }
    else if ( *vcKey == VK_TAB )
    {
        // move input focus to next dlg item

        ((CDialog*)GetParent())->NextDlgCtrl();
    }
}

History

Initial CodeProject release October 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
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.
Group type: Organisation

375 members


Comments and Discussions

 
GeneralMulti-line cell PinmemberTomas(cz)21-Apr-09 2:02 
GeneralRe: Multi-line cell PingroupThe Ultimate Toolbox21-Apr-09 8:35 

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

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140721.1 | Last Updated 6 Oct 2007
Article Copyright 2007 by The Ultimate Toolbox
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid