Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Another WTL Grid

0.00/5 (No votes)
1 Jun 2003 3  
A WTL Grid mostly aimed for use against databases.

Sample Image - WTLGrid2.png

Contents

Introduction

I'm coding a database application using WTL, and so far I've been using a standard list view for viewing data, and separate dialogs for editing. There are lots of different grids out there, but I didn't like the ones available for WTL very much. Not that they are bad or anything, they just didn't fit my needs. And instead of patching and fixing any existing ones to fit my need, it would probably be faster to make my own.

A little note about the demos. The Northwind demo requires a SQL server at localhost with the northwind database installed, and no password for the sa account. You can modify the connection string in MainFrm.h and recompile. The solutions are made with Visual Studio.NET 2003, so they won't open in older versions, but creating a new empty project and adding the files should be ok.

Features

  • Number of rows only limited by memory.
  • I've been testing with 100000 lines with no problems on my 2 GHz machine. Will also depend on the number of columns and your interacting code. Remember to use SetRedraw when adding many lines though.
  • Cells can be edited using standard edit control, combo box (either dropdown or dropdownlist), or DateTimePicker control.
  • Made for database users, and therefore everything uses _variant_t (and _bstr_t for strings).
  • Combo boxes use a lookup value to set the value of the column. The ID field is placed in the grid, and the grid displays and edits informative text fields.

There are lots of others things that I probably will add to this grid, but for now this is enough for my needs. I welcome any comments and suggestions you might have for improvements.

How to use

Simple Usage

Let me show you how to create the most basic grid. Here I start with a standard WTL AppWizard application, and replace the main forms view with a grid. After creating the grid I set the style to allow a context menu to be shown if you click the right mouse button in the grid.

Creating the grid

CGridCtrl m_view;

LRESULT CMainFrame::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, 
                        LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
    // ...

    m_hWndClient = m_view.Create(m_hWnd, rcDefault, NULL, 
        WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 
        WS_EX_CLIENTEDGE);
    m_view.SetExtendedGridStyle(GS_EX_CONTEXTMENU);
    // ...

}

Adding columns

m_view.AddColumn("Last Name",140,CGridCtrl::EDIT_TEXT);
m_view.AddColumn("First Name",140,CGridCtrl::EDIT_TEXT);

Lookup Columns

Now we will add another column where you can enter the sex of a person. Here you will see that we use more arguments to the AddColumn function. The first new parameter is alignment, and the last one is what data type this column uses. The default is VT_BSTR which we used on the first two columns. Now we will store the sex information as integer, so we use VT_I4.

We also tell the grid, what should be possible to choose from the combobox, we will add to the grid.

m_view.AddColumn("Sex",100,CGridCtrl::EDIT_DROPDOWNLIST,
                CGridCtrl::CENTER,VT_I4);
m_view.AddColumnLookup("Sex",1,"Male");
m_view.AddColumnLookup("Sex",2,"Female");

We should now have a grid where we can enter a person's last name, first name, and sex.

Adding rows

You add rows by calling AddRow and SetItem. In this example, I use SetRedraw before and after adding the row. For just one row, this wouldn't be necessary, but for many rows this is a must.

m_view.SetRedraw(FALSE);
long nItem = m_view.AddRow();
m_view.SetItem(nItem,"Last Name","Henden");
m_view.SetItem(nItem,"First Name","Bj�rnar");
m_view.SetItem(nItem,"Sex",1);
m_view.SetRedraw(TRUE);

What about events?

For catching events, I created a class CListener that you inherit from. This class is not only used for events, but also to query information about cell background color.

class CListener {
public:
    virtual bool OnRowChanging(UINT uID,long nRow);
    virtual void OnRowChanged(UINT uID,long nRow);
    virtual void OnEdit(UINT uID,long nRow);
    virtual bool OnDeleteRow(UINT uID,long nRow);
    virtual void OnNewRow(UINT uID,long nRow);
    virtual void OnModified(UINT uID,LPCTSTR pszColumn,_variant_t vtValue);
    virtual void OnRowActivate(UINT uID,long nRow);
    virtual COLORREF GetCellColor(UINT uID,long nRow,LPCTSTR pszColumn);
    virtual bool OnValidate(UINT uID);
};

The following example will show you how to be notified when a row is deleted from the grid, and set a new background color for rows that are modified.

First inherit CMainFrame from CGridCtrl::Clistener, and then override the functions you want.

class CMainFrame : public CFrameWindowImpl<CMainFrame>, ..., 
                                    public CGridCtrl::CListener

LRESULT CMainFrame::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, 
                        LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
    // ...

    m_view.SetListener(this);
    // ...

}

virtual bool OnDeleteRow(UINT uID,long nRow) {
    CString str;
    str.Format("Do you want to delete row %d?",nRow);
    // Returning false will abort the delete

    return IDYES==AtlMessageBox(m_hWnd,(LPCTSTR)str,
            IDR_MAINFRAME,MB_YESNO|MB_ICONQUESTION);
}

virtual COLORREF GetCellColor(UINT uID,long nRow,LPCTSTR pszColumn) {

    _variant_t vt = m_view.GetItem(nRow,"Sex");
    if(!m_view.IsNull(vt)) {
        if((long)vt==1)
            // Blue-ish for males

            return RGB(192,192,255);
        else
            // And red-ish for females

            return RGB(255,192,192);
    }
    // Return (COLORREF)-1 to use default colors

    return (COLORREF)-1;
}

Function reference

Here is a brief function reference. I will only list the function names, and a short description of what it does.

void AddColumn()

Adds a column to the grid. You can't add columns if there are rows in the grid. The last parameter to this function is the name of the column, which can be used as arguments to other functions. If this is omitted, the column title is used as name.

void AddColumnLookup()

Adds a lookup value to a column. This doesn't have to be columns that use dropdownlists, but could be any column.

long AddRow()

Adds a row to the grid and returns the row number inserted. Use this return value to set individual cell values on this row.

void ClearModified()

When cells are edited they set the row status to modified. Call this function to reset the specified row to, not modified. Specify -1 for all rows.

void DeleteAllColumns()

Deletes all columns.

void DeleteAllItems()

Deletes all rows.

void EnsureVisible()

Display the row in the visible area of the grid.

long GetColumnCount()

Returns the number of columns in the grid.

_variant_t GetEditItem()

When in edit mode, call this to get the current value of one of the cells being edited.

_variant_t GetItem()

Returns the value of the row and cell.

bool GetModified()

Returns true if the row is modified. Use -1 for all rows.

long GetRowCount()

Returns the number of rows in the grid.

long GetSelectedRow()

Returns the number of the selected row, and -1 if no row is selected.

bool IsNull()

A static function that can be used to check if a _variant_t is null. Returns true for VT_NULL and VT_EMPTY.

BOOL PreTranslateMessage(MSG* pMsg)

This should be called from your main frame PreTranslateMessage function. Without it, tab between cells will not work. If you use this grid in a modal dialog, tabs will also not work, since PreTranslateMessage can't be called. Open the dialog modeless instead, and disable the parent window.

void SetColumnFocus()

Set focus to a column. Only matters when in edit mode. Nice if validation for a field fails, and you want to focus the missing value.

void SetItem()

Set the value of a cell.

void SetListener()

Must be set to a class inherited from CGridCtrl::CListener.

void SetNull()

Static function that can be used to set the value of a _variant_t to null.

Credits

  • Uses atlgdix.h (CMemDC) by Bjarke Viksoe.
  • Inspired by Noel Frankinet and his WTL Grid, and used some of his code for drawing and column dragging.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here