dcsimg
December 8, 2016
Hot Topics:

A Better Approach to WinCE/Pocket PC Forms

  • December 18, 2002
  • By Nancy Nicolaisen
  • Send Email »
  • More Articles »

We have a CommandBands control, the control is initialized with bands, and now all that remains is to insert the form's controls and set their behaviors. A word about the strategy behind the "form" building steps is in order her. We save conserve screen real estate in a couple of different ways using command bands. First, and most obvious is the CommandBands control itself is fairly condensed. The second is that we eliminate the need for control captions by making all of the controls in the form list boxes or combo boxes.

If the field really is a list ( that is, the user must pick one or more items, but can't add items of their own), then the first item in the list is the string that would normally be the caption text for the control if we were using a dialog based form.. If, on the other hand, the user can type input to the control (the combo box style ), then the first item in the combo box list is the caption, and user input to the edit control is always inserted at the end of the list.

Initially, all the controls are displayed with the caption string selected, which has the effect of labeling the controls, but without using additional screen real estate to do so. If the user visits a control and provides input, we change the current list selection from the field's caption string to the user's typed input or list selection. This has the dual advantages of making it easy for the user to see where she has entered data and easy for the programmer to test for and validate input.

Now let's set up the controls for the form. Here's the initialization array where we store the initialization information for each control.

// Setup information for the controls that implement
//the fields of the forms
const struct CmdBarParms structCmdBarInit[] = 
{
  //Ctrl ID  //Label text //Ctrl Styles   //String Index  //#strings

  IDC_NAME,
          IDS_NAME,    ES_AUTOHSCROLL,    NULL,             0,
  IDC_BADGE,   
          IDS_BADGE,   ES_AUTOHSCROLL,    NULL,             0,
  IDC_DESC,
          IDS_DESC,    ES_MULTILINE | ES_AUTOVSCROLL,
                                          NULL,             0,
  IDC_CAT,    
          IDS_CAT,     CBS_DROPDOWNLIST,  IDS_CAT1,         2,
  IDC_MODE_TRAVEL,
          IDS_MODE_TRAVEL, CBS_DROPDOWNLIST,    
                                          IDS_MODE_TRAVEL1,
                                                            3,
  IDC_WHERE_SEEN,
          IDS_WHERE_SEEN, CBS_DROPDOWNLIST,  
                                          IDS_WHERE1        3,
  IDC_PHYS_EVIDENCE,
          IDS_PHYS_EVIDENCE,
                       CBS_DROPDOWNLIST,   
                                          IDS_PHYS_EVIDENCE1, 
                                                            3,
  IDC_OFFICE,   
          IDS_OFFICE,  CBS_DROPDOWNLIST,     
                                          IDS_OFFICE1,      3,
  IDC_ABDUCTIONS,
          IDS_ABDUCTIONS, CBS_DROPDOWNLIST,    
                                          IDS_ABDUCTIONS1,
                                                            3,
  IDC_FRIENDLY,  
          IDS_FRIENDLY, CBS_DROPDOWNLIST, 
                                          IDS_FRIENDLY1,    3,
  IDC_TALKATIVE,   
          IDS_TALKATIVE, CBS_DROPDOWNLIST,  
                                          IDS_TALKATIVE1,   3,
  IDC_APPEARANCE,    
          IDS_APPEARANCE, CBS_DROPDOWN,   IDS_APPEARANCE1,
                                                            5
};

In order to set up the controls, we loop the bands of the CommandBand control and the control initialization array, inserting controls and setting their attributes using the control ID, label text string, and control styles specified in the structCmdBarInit array.

//Move past the menu bar and set the control behaviors
for (i = 1; i < nBands; i++) 
{
   hwndBand = CommandBands_GetCommandBar (hwndCB,i);
   CommandBar_InsertComboBox (hwndBand, hInst, 
                              prbi[i].cx - 6, 
                              structCmdBarInit[i].lStyles, 
                              IDC_COMBO_BASE_ID + (i - 1), 0);

Next, we initialize each control with it's list of strings. If the control is intended to behave as an edit control, it has only 1 string: its caption. If the control is a list, its array entry specifies its caption, a manifest constant that gives the index of its first string resource in the string table, and a count of the strings.

In order to initialize the control, you must get its handle from the band which contains it.

//get a handle to the combo in this band
hwndCombo = GetDlgItem(hwndBand,IDC_COMBO_BASE_ID + (i - 1));

As a recap, the steps necessary to gain access to an individual control are:

  • Get a handle to a band by calling CommandBands_GetCommandBar()
  • Get a handle to the dialog control GetDlgItem() for the hwnd returned by the previous step

Next load and select the string for the caption. (Every control needs this initializtion. )

//get the caption string
LoadString(hInst, structCmdBarInit[i - 1].uiCaption, 
           (LPTSTR)&tszCaptionBuff,sizeof(tszCaptionBuff));

//insert the label string
SendMessage (hwndCombo, CB_INSERTSTRING, 0, 
            (long)&tszCaptionBuff);
//highlight the caption
SendMessage (hwndCombo, CB_SETCURSEL, 0, 0);

Test the number of list strings. If this control needs a list of selection items, we'll insert the list strings now.

//does this combo have a string list?
if(structCmdBarInit[i - 1].iNumStrings)
{

The strings are stored in the resource file in the order that they appear in the list, and so have consecutive resource Ids. We load the strings by incrementing the based string ID and limit the loop iteration using the count of strings, both of which are stored in the structCmdBarInit structure.

    //if so, insert them in the combo
    for( j = 0; j < structCmdBarInit[i - 1].iNumStrings; j ++ )
    {
      LoadString(hInst, structCmdBarInit[i - 1].iStringIndexBase + j,
          (LPTSTR)&tszCaptionBuff,sizeof(tszCaptionBuff));
      //add strings to the end of the list
      SendMessage (hwndCombo, CB_INSERTSTRING, -1, 
          (long)&tszCaptionBuff);
    } //end for(iNumStrings)
  }//end if(iNumStrings)
}

There you have it. We created a for using controls of fixed size and order, all of which are fully displayed when the form is created. To query the controls for input, you use the same sort of looping construction that we saw in the initialization process, followed with a call to GetDlgItemText() to retrieve user input.. Here's a code fragment that demonstrates how to retrieve input from a control in a CommandBand:

//a stack based buffer for the control's input
TCHAR szSelString[48];

   //get a handle to the bar contained by the band at index i
     hwndBand = CommandBands_GetCommandBar (hwndCB,i);

     //get a handle to the combo in this band
     hwndCombo = GetDlgItem(hwndBand,IDC_COMBO_BASE_ID + (i - 1));

    //ask the list what is selected 
    j = SendMessage(hWndCombo, CB_GETCURSEL , 0, 0 );

    //copy the string at index j to the buffer
    SendMessage(hWndCombo, CB_GETLBTEXT , j, (long)&szSelString );

Here are a couple of things to note about this code fragment. First, notice that the type of the buffer szSelString is TCHAR. Control strings, filenames and the like are Unicode under CE. Consistently using TCHAR types when dealing with controls saves you from having to think about the physical size of strings you are manipulating, and thus greatly reduces the likelihood of memory overwrites. Second, this code work for single selection list strings, but not for multiple selection string. Multiple selection list don't have a "current" selection. For multiple selection lists, you must first query the control for number of selections, allocate a buffer to hold an array of selection item indices, get the sel indices, and then loop through the list or combo control and get the strings. Here's a code fragment that demonstrates this strategy:

//get the count of selections
j = SendMessage(hWndCombo, LB_GETSELCOUNT , 0, 0 );

//allocate an integer array to hold the selection indices
piSelIndices = (LPINT)LocalAlloc( LPTR, sizeof(int) * j;
//ALWAYS check the return of an allocation call
if( ! piSelIndices )
{
   //no alloc, fail & bail
   return FALSE;
}

//get the array of sel indices
SendMessage(hWndCombo, LB_GETSELITEMS, j, (long) piSelIndices);

//loop thru the array and get the strings at the selection indices
for( k = 0; k < j; k++, piSelIndices++ )
{
   //copy the string at index j to the buffer
   SendMessage(hWndCombo, LB_GETLBTEXT , j, (long)&szSelString );
         .
   //do something with the string
          .
}

Wrapping Up

This is a tidy solution for displaying forms on small devices, but again we face limitations of screen real estate. What if your form simply can't be condensed sufficiently to fit on single screen of command bands? In the next installment, we'll learn how to create "pages" of command bands. I'll show you how to set up the controls so that users can move back and forth between screens of bands, using controls that look and behave like the "forward" and "back" buttons on a web browser.

Download the Source

DataBands.zip - 7 kb

About the Author

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, entry time data validation.

In addition to writing for Developer.com, she has written several books including Making Win 32 Applications Mobile. She has also written numerous articles on programming technology for national publications including Dr. Dobbs, BYTE Magazine, Microsoft Systems Journal, PC Magazine; Computer Shopper, Windows Sources and Databased Advisor.

# # #





Page 3 of 3



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Sitemap | Contact Us

Thanks for your registration, follow us on our social networks to keep up-to-date
Rocket Fuel