A Validating Edit Control

Tooltips

I found that when there are many controls on the dialog, and several of them affect whether or not a control (such as the OK button) is enabled, it is often quite informative to use a ToolTip to specify the text explaining why the control is not enabled. Often, there are several causes. In this case, the problem is which one to display. ToolTips have a limited string length they can display, and characters beyond this will not be displayed. My strategy is to adopt a mechanism that involves a rule-based system that examines the conditions and displays the first condition that has disabled the control. Sometimes I arrange these rules so that the most common, or easiest-to-fix, condition is the one displayed first.

To enable ToolTips, you must call the function EnableToolTips(TRUE) in the OnInitDialog handler. In addition, I do the ToolTip by using a callback function. This means I must add the following message handler to my MESSAGE_MAP, outside the magic comments:

//}}AFX_MSG_MAP
ON_NOTIFY_EX(TTN_NEEDTEXT, 0, OnToolTipNotify)

The handler is defined as follows:

BOOL CValidatorDlg::OnToolTipNotify(UINT, NMHDR * pNMHDR, LRESULT *)
   {
    TOOLTIPTEXT * pTTT = (TOOLTIPTEXT *)pNMHDR;
    HWND ctl = (HWND)pNMHDR->idFrom;

    UINT msg = 0; // set to message ID of text to display

    if(pTTT->uFlags & TTF_IDISHWND)
       { /* display request */
        UINT id = ::GetDlgCtrlID(ctl);
        switch(id)
           { /* id */
            case IDC_SAMPLE:
                 // This is the 'OK' button
                 // We search for reasons it might be disabled
                 // Only the first reason counts.
                 // Our limit is the tooltip text length, so we
                 // present the errors in the order we think the
                 // user might most easily fix them. For example,
                 // the tab order

Within each case for each control I put the rules, or a call on a function that computes the rules, for that control. For example, to make the messages clearer, I have two internal state functions in the CFloatingEdit control, one of which tells me if the value is syntactically valid and one of which tells me if the value is semantically valid. The routine IsValid returns TRUE only if the value is both syntactically and semantically valid. This allows me to report in more detail why the value is not valid. For the semantic check, I call the same function that the child validity check used, which returns me a string ID for a string to display if there is an error, or 0 if there is not an error. Ultimately, this value is stored in the variable msg. If this value is 0, there is nothing to display, and I return FALSE from the handler; otherwise, I set up some fields in the structure passed in, and return TRUE.

if(msg == 0)
   return FALSE;
pTTT->lpszText = MAKEINTRESOURCE(msg);
pTTT->hinst = AfxGetResourceHandle();
return TRUE;

This causes the string designated by the string ID stored in msg to be displayed as the ToolTip.

In a real application, the text would have been more informative, for example, "Temperature value is not in correct format", but the generalization to that should now be obvious.

You might also like...

Comments

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“Walking on water and developing software from a specification are easy if both are frozen.” - Edward V Berard