Adding Database Attribute Rows to the List Control

Adding Database Attribute Rows to the List Control

In this lesson, you'll see how to add database attribute rows to the list view control that you constructed and initialized in previous examples. You'll explore these techniques by examining the functioning of the RemoteDBScan example. Sources are available on this Web site.

The Anatomy of the Listview Control

The Listview Control treats its contents as a matrix, where iItem is the zero-based row index and iSubItem is the zero-based column index. Although the CListViewEx class on which your view is based appears to the user to handle the list control contents as a collection of horizontal rows, the underlying mechanism actually organizes and manages content as a collection of row/column matrix elements. For this reason, when you add the "row" containing a database's attributes, you must add each item separately.

Adding a list item is not unlike adding a column to the list control, in that it is a two-step process. First, you initialize an LV_ITEM structure that defines the item's attributes; then you add the item with a call to the ClistCtrl member InsertItem().

Here's the typedef for the LV_ITEM structure:

typedef struct _LVITEM {
        UINT   mask;        //flags that define which members are
                            //valid
        int    iItem;       //0-based row index in list ctrl matrix
        int    iSubItem;    //0-based column index in list control
                            //matrix
        UINT   state;       //the item's state, state image, and
                            //overlay image
        UINT   stateMask;   //tells which bits of the state are
                            //valid
        LPTSTR  pszText;    //item caption
        int    cchTextMax;  //caption buffer length
        int    iImage;      //index of image in image list
        LPARAM lParam;      //used for app-specific data
      } LVITEM, FAR *LPLVITEM;

Tables 1 and 2 show the possible values for the mask and state members of the LV_ITEM structure:

Table 1: LV_ITEM Mask Flags and their Meanings

Mask Flag Constant Meaning
LVIF_TEXT pszText is valid
LVIF_IMAGE iImage is valid
LVIF_INDENT iIndent is valid
LVIF_PARAM lParam is valid
LVIF_STATE state is valid

Table 2: LV_ITEM State Flags and their Meanings

ItemState Flag Constant Meaning
LVIS_ACTIVATING Item is activating on LVN_ITEMACTIVATE notification
LVIS_CUT Item is marked for cut and paste
LVIS_DROPHILITED Item is a drag and drop target
LVIS_FOCUSED Item has the input focus
LVIS_SELECTED Item is selected

Now, take a tour of the AddRowToList() member function.

BOOL CRemoteDBScanView::AddRowToList(CEOID enumCeoid,
                                     CEOIDINFO * poidInfo )
{

    LV_ITEM         lvitem;    //List View Item Descriptor struct

    //Get the List Control Object
    CListCtrl& ListCtrl = GetListCtrl();
    
    // add at the last row
    lvitem.iItem     = ListCtrl.GetItemCount();
    lvitem.mask      = LVIF_TEXT | LVIF_STATE;
    lvitem.stateMask = LVIS_FOCUSED;
    lvitem.state     = LVIS_FOCUSED;

This function is designed to add a full row at the bottom of the list control, so your first step is to get a count of list control items. Recall that "items" are synonymous with rows in this context, whereas subitems are synonymous with columns.

The first item you add is the database name. This was returned in the CEOIDINFO structure member CEDBASEINFO's szDbaseName member. The returned name string is in Unicode, so you have to translate it to multibyte character format before inserting it in the list control. After translation, you set the address of the MBCS string in lvitem.pszText, and call InsertItem().

//add attribute string to bottom row of the listctl
//loop thru the subitems
char szTempBuff[512];

lvitem.iSubItem = 0;
wcstombs(szTempBuff, poidInfo->infDatabase.szDbaseName,
         sizeof(szTempBuff));
lvitem.pszText = szTempBuff;
ListCtrl.InsertItem(&lvitem);

The next step is a key strategy. It helps you optimize performance and makes opening the database to enumerate its records a bit more convenient. You set the OID value for this database as item data in the list control cell that holds the database name. Here's why you do this.

CE object identifiers are permanent attributes of the objects they identify. Put another way, they are created when the object is created, and stick with the same object throughout its lifetime. For your purposes, they are worth preserving because you can open a database (or a file) by CEOID as well as by name. Preserving the CEOID allows you to open the database without having to translate the name string in the list control back to Unicode. Also, opening the database by CEOID is a good bit faster than opening by name.

After the item has been added, you set its item data like this:

//save the CEOID for this database in item data
ListCtrl.SetItemData( lvitem.iItem, (DWORD)enumCeoid );

Now, add the rest of the database attributes to the row. All you really have to do differently for the successive items is increment the lvitem.iSubItem, de-reference the applicable member of the CEDBASEINFO structure, and format the datum using sprintf().

lvitem.iSubItem = 1;
sprintf( szTempBuff, "%li", poidInfo->infDatabase.dwDbaseType);
lvitem.pszText = szTempBuff;
ListCtrl.SetItem(&lvitem);

lvitem.iSubItem = 2;
sprintf( szTempBuff, "%x", poidInfo->infDatabase.dwFlags);
ListCtrl.SetItem(&lvitem);

lvitem.iSubItem = 3;
sprintf( szTempBuff, "%i", poidInfo->infDatabase.wNumRecords);
ListCtrl.SetItem(&lvitem);

lvitem.iSubItem = 4;
sprintf( szTempBuff, "%li", poidInfo->infDatabase.dwSize);
ListCtrl.SetItem(&lvitem);

lvitem.iSubItem = 5;
CTime ctLastWrite(poidInfo->infDatabase.ftLastModified );
CString csLastWrite = ctLastWrite.Format("%A, %B %d, %Y" );
sprintf( szTempBuff, "%s", csLastWrite.GetBuffer
       ( csLastWrite.GetLength()));
ListCtrl.SetItem(&lvitem);

lvitem.iSubItem = 6;
sprintf( szTempBuff, "%x", enumCeoid);
ListCtrl.SetItem(&lvitem);

return(TRUE);

Looking Ahead

Having the mechanics of adding a row to the list control in hand, you are ready to retrieve records from the CE database. You'll how see how to do that in the next installment.



About the Author

Nancy Nicolaisen

Nancy Nicolaisen is a software engineer who has designed and implemented highly modular Windows CE products that include features such as full remote diagnostics, CE-side data compression, dynamically constructed user interface, automatic screen size detection, and entry time data validation. In addition to writing for Developer.com and CodeGuru, she has written several books, including Making Win 32 Applications Mobile.

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • The explosion in mobile devices and applications has generated a great deal of interest in APIs. Today's businesses are under increased pressure to make it easy to build apps, supply tools to help developers work more quickly, and deploy operational analytics so they can track users, developers, application performance, and more. Apigee Edge provides comprehensive API delivery tools and both operational and business-level analytics in an integrated platform. It is available as on-premise software or through …

  • Application and data integration doesn't have to be slow and expensive. Learn how cloud-based integration platforms dramatically speed results and lower costs in this white paper by Bloor Research.

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds