GetCurSel() for a CComboBox is returns 2 different values on consecutive calls 
Author Message
 GetCurSel() for a CComboBox is returns 2 different values on consecutive calls

I am trying to develop a dropdown combobox that will open up when sufficient
leading characters have
been entered to uniquely match one of the strings. This was working fine
until I added a PreTranslateMessage() handler to look for an Enter (return)
key which would close the combobox dropdown. I want to use this in a dialog
where the Enter key will do the default action. Without this modification,
the user has to hit the enter key twice, once to close the drop down and
again for the default OnOK action of the dialog. Thus I look for the Return
key and close the drop down. It's at this point that the GetCurSel() returns
a -1 for some funny reason.

This is the listing for this message handler:

////////////////////////////////////////////////////////////////////////
//
// we need to check for backspace or delete. when we see
// one of these characters, we don't do the autocomplete
// since the same text would be written over the deleted stuff
//
BOOL
CAutoComboBox::PreTranslateMessage(MSG* pMsg)
{
   // if we have a key pressed and we are autocompleting
   if(pMsg->message == WM_KEYDOWN) {
       int key = pMsg->wParam;
       if(m_bAutoComplete) {
           // set to not autocomplete on the next real character
           if(key == VK_DELETE || key == VK_BACK) m_bAutoComplete = false;
       }
       // ?? remove
       int iSelectedRow = GetCurSel();
       int iCount = GetCount();
       TRACE(_T("PreTranslate1::m_iSelectedRow=%d: iSelectedRow=%d\n")
        , m_iSelectedRow, iSelectedRow);
       TRACE(_T("Key=%d: Count=%d\n"), pMsg->wParam, iCount);

       // if we have the enter key, close the drop down here so that
       // we only have to hit enter once
       if(key == VK_RETURN) {

           // this is due to a problem of sail numbers 1 and 100. the
           // iSelectedRow is sometimes CB_ERR for an unknown reason
           // and the nested SelChange message will change the internal
           // selected row (m_iSelectedRow)
           int iSelectedRowSave = m_iSelectedRow;
           ShowDropDown(FALSE);
           // if closing the drop down has changed the selected row
           if(m_iSelectedRow != iSelectedRowSave) {
               m_iSelectedRow = iSelectedRowSave;
           }
       }
       // ?? remove
       iSelectedRow = GetCurSel();
       TRACE(_T("PreTranslate2::m_iSelectedRow=%d: iSelectedRow=%d\n")
        , m_iSelectedRow, iSelectedRow);
   }
   return CComboBox::PreTranslateMessage(pMsg);

Quote:
}

The TRACEs are for me to try and track down what is happening. I've also
added code to compensate for
the bad value of the selected row.

The ShowDropDown(FALSE) issues an CBN_SELCHANGE notification messsage that I
have connected to my own routine as follows:

void
CAutoComboBox::OnSelChange()
{
   int iSelectedRow = GetCurSel();
   int iCount = GetCount();

   // ?? remove
   TRACE(_T("OnSelChange1::iSelectedRow=%d: m_iSelectedRow=%d\n")
    , iSelectedRow, m_iSelectedRow);

   // only change the selected row if a real selection
   if(iSelectedRow >= 0) {
       m_iSelectedRow = iSelectedRow;
   }
   // make sure that we only use a good row
   else if(m_iSelectedRow < iCount) {
       SetCurSel(m_iSelectedRow);
   }
   else {
       // this indicates no current selection
       m_iSelectedRow = -1;
   }

   // ?? remove
   CString line;
   // get the text from the user input
   GetWindowText(line);

   // ?? remove
   iSelectedRow = GetCurSel();
   TRACE(_T("OnSelChange2::iSelectedRow=%d: m_iSelectedRow=%d: line=%s\n")
    , iSelectedRow, m_iSelectedRow, (LPCSTR) line);

Quote:
}

My combobox has 15 entries of which the first 3 lines are as follows:

   0
   1
   100
   ...

and I type in 1 and then a 0. The first 1 matches the second line. The
second character, the 0, then
allows the unique match to the 100. At this point I hit the Enter key to do
the selection.

Now the output in the debug window is as follows:

...
1> PreTranslate1::m_iSelectedRow=-1: iSelectedRow=-1
2> Key=49: Count=15
3> PreTranslate2::m_iSelectedRow=-1: iSelectedRow=-1
4> SelectedRow: 1 Line: 1 Matched Text: 1
5> PreTranslate1::m_iSelectedRow=1: iSelectedRow=-1
6> Key=48: Count=15
7> PreTranslate2::m_iSelectedRow=1: iSelectedRow=-1
8> SelectedRow: 2 Line: 10 Matched Text: 100
9> PreTranslate1::m_iSelectedRow=2: iSelectedRow=-1
10> Key=13: Count=15
11> OnSelChange1::iSelectedRow=1: m_iSelectedRow=2
12> OnSelChange2::iSelectedRow=1: m_iSelectedRow=1: line=100
13> PreTranslate2::m_iSelectedRow=2: iSelectedRow=1

The 1 key is listed as 49. Line 4 comes from the matching part of the code
and says that we have selected
line 1 by matching a text string of "1". The next character the zero or key
48 shows up as the PreTranslate1:: of line 5. Here the iSelectedRow is -1 or
CB_ERR. There really is a selected row though, row one. We continue through
to the Return (13) on line 10 and again the selected row is returned as
CB_ERR or -1. This also shows the OnSelChange action as a result of the
ShowDropDown(FALSE). In this code, the GetCurSel() returns a 1 (line 11
shows the iSelectedRow at this point). This is the selection of two
characters ago!

I ran Spy to log the messages that were being sent to the combobox and got
the following:

<00001> 00000A14 S CB_GETCURSEL
<00002> 00000A14 R CB_GETCURSEL index:CB_ERR
<00003> 00000A14 S CB_GETCOUNT
<00004> 00000A14 R CB_GETCOUNT cItems:15
<00005> 00000A14 S CB_GETCURSEL
<00006> 00000A14 R CB_GETCURSEL index:CB_ERR
<00007> 00000A14 S ..CB_FINDSTRING indexStart:0 lpszFind:0096AF8C ("1")
<00008> 00000A14 R ..CB_FINDSTRING index:1
<00009> 00000A14 S ..CB_GETLBTEXTLEN index:1
<00010> 00000A14 R ..CB_GETLBTEXTLEN cchText:1
<00011> 00000A14 S ..CB_GETLBTEXT index:1 lpszBuffer:0096AC6C
<00012> 00000A14 R ..CB_GETLBTEXT cchText:1 lpszBuffer:0096AC6C ("1")
<00013> 00000A14 S ..CB_SHOWDROPDOWN fShow:True
<00014> 00000A14 R ..CB_SHOWDROPDOWN lResult:True
<00015> 00000A14 S ..CB_SETCURSEL index:1
<00016> 00000A14 R ..CB_SETCURSEL lResult:0001
<00017> 00000A14 S ..CB_SETEDITSEL ichStart:1 ichEnd:65535
<00018> 00000A14 R ..CB_SETEDITSEL lResult:True
<00019> 00000A14 S CB_GETCURSEL
<00020> 00000A14 R CB_GETCURSEL index:CB_ERR
<00021> 00000A14 S CB_GETCOUNT
<00022> 00000A14 R CB_GETCOUNT cItems:15
<00023> 00000A14 S CB_GETCURSEL
<00024> 00000A14 R CB_GETCURSEL index:CB_ERR
<00025> 00000A14 S ..CB_FINDSTRING indexStart:0 lpszFind:0096AF8C ("10")
<00026> 00000A14 R ..CB_FINDSTRING index:2
<00027> 00000A14 S ..CB_GETLBTEXTLEN index:2
<00028> 00000A14 R ..CB_GETLBTEXTLEN cchText:3
<00029> 00000A14 S ..CB_GETLBTEXT index:2 lpszBuffer:0096AC6C
<00030> 00000A14 R ..CB_GETLBTEXT cchText:3 lpszBuffer:0096AC6C ("100")
<00031> 00000A14 S ..CB_FINDSTRING indexStart:2 lpszFind:0096AF8C ("10")
<00032> 00000A14 R ..CB_FINDSTRING index:2
<00033> 00000A14 S ..CB_SHOWDROPDOWN fShow:True
<00034> 00000A14 R ..CB_SHOWDROPDOWN lResult:True
<00035> 00000A14 S ..CB_SETCURSEL index:2
<00036> 00000A14 R ..CB_SETCURSEL lResult:0002
<00037> 00000A14 S ..CB_SETEDITSEL ichStart:2 ichEnd:65535
<00038> 00000A14 R ..CB_SETEDITSEL lResult:True
<00039> 00000A14 S CB_GETCURSEL
<00040> 00000A14 R CB_GETCURSEL index:CB_ERR
<00041> 00000A14 S CB_GETCOUNT
<00042> 00000A14 R CB_GETCOUNT cItems:15
<00043> 00000A14 S CB_SHOWDROPDOWN fShow:False
<00044> 00000A14 S ....CB_GETCURSEL
<00045> 00000A14 R ....CB_GETCURSEL index:1
<00046> 00000A14 S ....CB_GETCOUNT
<00047> 00000A14 R ....CB_GETCOUNT cItems:15
<00048> 00000A14 S ....CB_GETCURSEL
<00049> 00000A14 R ....CB_GETCURSEL index:1
<00050> 00000A14 R CB_SHOWDROPDOWN lResult:True
<00051> 00000A14 S CB_GETCURSEL
<00052> 00000A14 R CB_GETCURSEL index:1
<00053> 00000A14 S .CB_GETDROPPEDSTATE
<00054> 00000A14 R .CB_GETDROPPEDSTATE fDropped:False

The first part is the matching of the strings. However, on both lines
<00019> and <00039> is the CB_GETCURSEL that returns the CB_ERR.

Line <00043> is the CBN_SHOWDROPDOWN and then we get the nested message to
the OnSelChange() routine which does the CB_GETCURSEL with a return of 1.

How can it be that on line <00039> the current selection is a CB_ERR but the
message almost immediately
after (albeit nested) returns a one.  The one is wrong though since the last
set was on line <00036>
where the current selection was set to 2.

It's a shame that we can't see inside the combo box code and so don't know
where the numbers are coming
from. If I could watch the place where the current selection was stored, I
could find the code that
changed it!

--
Edward E.L. MItchell
Pharsight Corp.
(508)771-0806
500 Ocean St., Unit 134,
Hyannis, MA 02601



Wed, 17 Mar 2004 02:36:56 GMT  
 
 [ 1 post ] 

 Relevant Pages 

1. Help - Calling ActiveX DLL function from VB and C++ returns different values

2. localtime function returns different values for different winnt operating systems

3. GetCommTimeouts is returns different values on different ports

4. Problem with using GetCurSel() on CComboBox

5. Problem with CComboBox::GetCurSel( ) It asserts!

6. GetClientRect returns different values each time app is run

7. Repost: How to assign consecutive values to struct

8. testing for consecutive values

9. BUG(?) with GetCurSel() and duplicate values

10. GetCurSel returns 0

11. CMonthCalCtrl::GetCurSel() returns wrong date

12. Consecutive gets() calls

 

 
Powered by phpBB® Forum Software