Click here to Skip to main content
15,860,859 members
Articles / Desktop Programming / WTL
Article

Another WTL Grid

Rate me:
Please Sign up or sign in to vote.
4.94/5 (37 votes)
1 Jun 20035 min read 238.4K   8.4K   101   67
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


Written By
Web Developer
Norway Norway
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
BugBug in dragging columns Pin
ud_1-Mar-12 21:57
ud_1-Mar-12 21:57 
Questionuse WTL CGridCtrl Pin
lihefei12-Nov-08 21:17
lihefei12-Nov-08 21:17 
GeneralUsing 2 CGridCtls in a dialog Pin
mtsirulnikov1-May-06 7:01
mtsirulnikov1-May-06 7:01 
GeneralCompiler error Pin
Alex.Y2-Jan-06 14:55
Alex.Y2-Jan-06 14:55 
GeneralLegal use of this in commercial product doesn't seem guaranteed Pin
kehlar30-Nov-05 12:24
kehlar30-Nov-05 12:24 
GeneralRe: Legal use of this in commercial product doesn't seem guaranteed Pin
Rick York30-Nov-05 13:13
mveRick York30-Nov-05 13:13 
GeneralRe: Legal use of this in commercial product doesn't seem guaranteed Pin
kehlar30-Nov-05 17:57
kehlar30-Nov-05 17:57 
Generalhelp! Pin
bohu11189-Nov-04 14:22
bohu11189-Nov-04 14:22 
Questionhow to compile under vc++6.0 Pin
Mandalay12-Jul-04 9:35
Mandalay12-Jul-04 9:35 
AnswerRe: how to compile under vc++6.0 Pin
RickyV1-Sep-04 16:32
RickyV1-Sep-04 16:32 
QuestionIs this supposed to work on VC++ 6? Pin
Daredevil5-Jun-04 8:17
Daredevil5-Jun-04 8:17 
AnswerRe: Is this supposed to work on VC++ 6? Pin
Daredevil5-Jun-04 9:20
Daredevil5-Jun-04 9:20 
GeneralRe: Is this supposed to work on VC++ 6? Pin
Masahiko Kanetaka11-Jul-04 23:39
Masahiko Kanetaka11-Jul-04 23:39 
AnswerRe: Is this supposed to work on VC++ 6? Pin
bytescout16-Jun-04 8:51
bytescout16-Jun-04 8:51 
GeneralGreat Work... but a little Bug... Pin
HumanOsc15-May-04 1:15
HumanOsc15-May-04 1:15 
GeneralCommercial use Pin
jweston30-Apr-04 23:48
jweston30-Apr-04 23:48 
GeneralRe: Commercial use Pin
Bjornar Henden2-May-04 19:28
Bjornar Henden2-May-04 19:28 
GeneralAdding items in the combo when the user press enter Pin
Gizz_0115-Apr-04 10:31
Gizz_0115-Apr-04 10:31 
GeneralCan't create CCellData Pin
Xuewu Liu4-Jan-04 15:17
Xuewu Liu4-Jan-04 15:17 
On my windows 2000(VS.net 2003),I can compile the demo project,but when I ran it,a debug failed assertion occured.
I traced the code and found that the code bellow failed in CCellDate::Create(),

m_hWnd = m_wndEdit.Create( m_column.m_grid,rcDefault,NULL,WS_CHILD|WS_TABSTOP|dwStyle,0 );

It seemed that the reason is the code bellow in CWindowImpl::Create()

ATOM atom = T::GetWndClassInfo().Register( &m_pfnSuperWindowProc);Confused | :confused:

But I can run the same compiled demo on Windows.NET 2003. Why?Eek! | :eek:
GeneralRe: Can't create CCellData Pin
jof400226-Jan-04 13:31
jof400226-Jan-04 13:31 
GeneralRe: Can't create CCellData Pin
Xuewu Liu25-Jul-04 0:13
Xuewu Liu25-Jul-04 0:13 
GeneralDrag and Drop Pin
creilly14-Nov-03 0:02
creilly14-Nov-03 0:02 
QuestionIs there any way to use it in Dialogs? Pin
zmeika20-Oct-03 4:32
zmeika20-Oct-03 4:32 
GeneralDestroy Window problem Pin
TFrancis1-Oct-03 8:59
TFrancis1-Oct-03 8:59 
GeneralRe: Destroy Window problem Pin
Marcus Mar8-Nov-04 23:40
sussMarcus Mar8-Nov-04 23:40 

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

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