[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 471
  • Last Modified:

auto complete

See the accepted answer here: http://www.experts-exchange.com/Q_21210092.html

My problem with the solution above is that I need to reference the listindex property of these combo boxes for other processing.
Obviously, if a selection is 'typed' instead of clicked, my listindex remains at -1.

I have 'gotten around' this with some of my smaller cbo's by looping through the list data until there is a match to the database entry and then setting the listindex to that integer's value (x).

Any other ideas on how to accomplish this?
0
sirbounty
Asked:
sirbounty
  • 28
  • 13
  • 4
  • +3
2 Solutions
 
gary_jCommented:
if the function in the previous accepted answer doesn't return the listindex (I didn't have the time to analyze it), then i'd loop through comparing the cbo.text property to the cbo.list property to find my match ...
0
 
David LeeCommented:
I grabbed the code from the previous question and stepped through it.  The listindex is being set, so I'm not sure what the problem is.  In the KeyPress event of the cbo add this line of code

    Debug.Print Combo1.ListIndex

immediately after

    KeyAscii = AutoMatchCBBox(Combo1, KeyAscii)

and you'll see what I mean.
0
 
sirbountyAuthor Commented:
Hmm - okay, perhaps my problem lies somewhere else....closer look tomorrow (code is at work).
Thanx all
0
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
sirbountyAuthor Commented:
This is what I witnessed when typing text in my combo...
keyascii   listindex
 0            -1          -->  I suppose this is when I first entered the box
 0             69        -->  I hit "r"
 0             73       --> then "o"
 13           -1       --> then <enter> to select "Rochester, NY" (see listindex got set back to -1... )  : (

You don't see anything in that code that is resetting this do you?
0
 
AzraSoundCommented:
Don't know if it helps, but I always used this function which returns the listindex via a passed in parameter:



Public Function ComboAutoComplete(ByRef cboBox As ComboBox, ByRef ListIndex As Long) As Boolean
    Dim lngItemNum          As Long
    Dim lngSelectedLength   As Long
    Dim lngMatchLength      As Long
    Dim strCurrentText      As String
    Dim strSearchText       As String
    Dim sTypedText          As String
    Const CB_LOCKED = &H255

    With cboBox
        If .Text = "" Then
            Exit Function
        End If
        Call LockWindowUpdate(.hwnd)
        If ((InStr(1, .Text, .Tag, vbTextCompare) <> 0 And Len(.Tag) = Len(.Text) - 1) Or (Left(.Text, 1) <> Left(.Tag, 1) And .Tag <> "")) And .Tag <> CStr(CB_LOCKED) Then
       
            strSearchText = .Text
            lngSelectedLength = Len(strSearchText)
       
            lngItemNum = SendMessage(.hwnd, CB_FINDSTRING, -1, ByVal strSearchText)
            ComboAutoComplete = Not (lngItemNum = -1)
       
            If ComboAutoComplete Then
                ListIndex = lngItemNum
                lngMatchLength = Len(.List(lngItemNum)) - lngSelectedLength
                .Tag = CB_LOCKED
                sTypedText = strSearchText
                .Text = .Text & Right(.List(lngItemNum), lngMatchLength)
                .Tag = sTypedText
                .SelStart = lngSelectedLength
                .SelLength = lngMatchLength
            End If
        ElseIf .Tag <> CStr(CB_LOCKED) Then
            .Tag = .Text
        End If
        Call LockWindowUpdate(0)
    End With
End Function
0
 
sirbountyAuthor Commented:
Azra - you mean in place of the other function I was using?  I'll give it a shot...thanx.
0
 
sirbountyAuthor Commented:
AzraSound - am I missing LockWindowUpdate?
Replacing this one for the prior doesn't seem to be working... :(
0
 
David LeeCommented:
How about this used in conjunction with Shauli's code?


Dim lngCurrentComboItem As Long

Private Sub Combo1_KeyPress(KeyAscii As Integer)
    KeyAscii = AutoMatchCBBox(Combo1, KeyAscii)
    lngCurrentComboItem = IIf(Combo1.ListIndex < 0, lngCurrentComboItem, Combo1.ListIndex)
    Debug.Print "Current Item: " & Combo1.List(lngCurrentComboItem) & " (" & lngCurrentComboItem & ")"
End Sub
0
 
ShauliCommented:
Hi sirbounty

If you need the listindex of the selected item from the combo, then add the following to the module:

In declaration area:
Public LineIndex As Integer

In the AutoMatchCBBox function, Add the marked line in the part of the code as  below:

    If bContinueSearch Then 'need to search
        Call VBComBoBoxDroppedDown(cbBox)  'open dropdown list
        lResult = SendMessage(cbBox.hwnd, CB_SELECTSTRING, -1, ByVal strFindThis)
        If lResult = CB_ERR Then 'not found
            cbBox.Text = strFindThis 'set cbBox as whatever it is
            cbBox.SelLength = 0 'no selected char(s) since not found
            cbBox.SelStart = Len(cbBox) 'set insertion position @ the end of string
        Else
            'found string, highlight rest of string for user
            cbBox.SelStart = Len(strFindThis)
            cbBox.SelLength = Len(cbBox) - cbBox.SelStart
            LineIndex = cbBox.ListIndex   '<<<<<<<<<<<<<<<<< this is the listindex of the selected item
        End If
    End If

So now the listindex of the selected item is in variable LineIndex

Hope this is what you were looking for,

S

0
 
aikimarkCommented:
As each valid letter is typed, you might consider the following actions:
1. Set the listindex = first listbox item matching the letters typed so far
2. Set the SelStart and SelLength values such that the remainder of the text will be overwritten with the user's next keystroke.

===============
Alternatively, you might trap the Enter key and set the listindex there, based on the best/first/closest match.
0
 
AzraSoundCommented:
You'll need this declaration plus any others you don't already have.  You should be able to find any of them in your API Viewer:

Public Declare Function LockWindowUpdate Lib "user32" Alias "LockWindowUpdate" (ByVal hwndLock As Long) As Long
0
 
sirbountyAuthor Commented:
Shauli - this appears to be working for me to an extent.  
However, I seem to be having a problem passing that value back to the appropriate combo box.
At present, I'm setting listindex to lineindex on cboinfo_lostfocus, but since I'm using control arrays, it's sometimes setting the value on the wrong box...

Private Sub cboInfo_LostFocus(Index As Integer)
    cboInfo(Index).ListIndex = LineIndex  'breaking at this point, listindex is still -1  : (
    If cboInfo(Index).ListIndex > -1 Then
        cboInfo_Click (Index)
    End If
End Sub
0
 
ShauliCommented:
You should break it one line down, if you want to see if listindex got the value from lineindex.
LineIndex gets its value the minute the entire line was selected, which means the function found a match in the combo list.
However, if you want, you can set the LineIndex as array, and asign the index to the LineIndex, as in LineIndex(thecomboindex).

S
0
 
sirbountyAuthor Commented:
Well, that's an idea...perhaps I'll try that.
But I'm baffled as to why listindex is getting 'reset' to -1 in the first place...
Any way I can determine more closely 'when' this is happening?  I tried adding a watch, but I don't think it worked...
0
 
ShauliCommented:
Well, I'm trying to simulate it, so I put two combos on my form, and played with the autoselect, and put this code also:

Private Sub Combo1_LostFocus(Index As Integer)
Combo1(Index).ListIndex = LineIndex
Label1.Caption = Combo1(Index).ListIndex
End Sub

..and the label always shows the correct ListIndex... :( it looks like something else is affecting it.

S
0
 
sirbountyAuthor Commented:
Hm...I was afraid you'd say that....<sigh>
Okay - hunt and peck game, here I go... :(
0
 
aikimarkCommented:
Are you seeing this behavior with a breakpoint somewhere in your code?  If so, you might want to test it as compiled code.  Windows messages and events can happen in a different order when debugging.
0
 
sirbountyAuthor Commented:
Yep - seeing it even when running a full compile... : (
0
 
ShauliCommented:
So, Sir, I think I saw another paq of yours, using the combo in a query or something? If that is why you need the listindex, then why not use the LineIndex var directly where you need the index, instead of the listindex? Especially if you are gonna use an array of those LineIndexes, corresponding to the combo index? Or maybe I'm totally off route hear...

S
0
 
sirbountyAuthor Commented:
Yeah see - I have these combos that when you 'click' them, they perform other functions/routines...
If I 'type' in them, it appears that listindex isn't set...
0
 
AzraSoundCommented:
Did you try my routine?
0
 
sirbountyAuthor Commented:
I'm sorry AzarSound, I 'tried' to, but I suppose I'm not as familiar with it...perhaps if you could elaborate just a bit?
I'll put it back in (commented out for the moment) and let you know where I'm stuck...
0
 
AzraSoundCommented:
You still have the function above.  These are all the declarations required:

Public Declare Function LockWindowUpdate Lib "user32" (ByVal hwndLock As Long) As Long
Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long

Public Const CB_FINDSTRING = &H14C



In use, it would look like this:

Private Sub cboInfo_Change(Index As Integer)
    Dim lngListIndex As Long

    If ComboAutoComplete(cboInfo(Index), lngListIndex) = True Then
        'lngListIndex contains the current ListIndex of the displayed item
    End If
End Sub
0
 
sirbountyAuthor Commented:
CB_FINDSTRING - variable not defined...how do I declare this?
Cause if I just put
DIM CB_FINDSTRING
then it won't let me type at all... :(
0
 
AzraSoundCommented:
I placed it above.  It needs to be public in a bas module with the rest of your API declarations.
0
 
sirbountyAuthor Commented:
Ok...brb..
0
 
sirbountyAuthor Commented:
This is how I'm currently calling it - could my problem be here?

Private Sub cboInfo_KeyPress(Index As Integer, KeyAscii As Integer)
    KeyAscii = ComboAutoComplete(cboInfo(Index), cboInfo(Index).ListIndex)
End Sub
0
 
sirbountyAuthor Commented:
Hmm...it doesn't seem to be allowing any character input and .text is always = "", thus exiting the function...
0
 
AzraSoundCommented:
You declare a variable, as in my example, which will then hold the listindex once the function returns.  Also, this should be called from the Change event.  Notice I declared the variable "Dim lngListIndex As Long" in my sample above.

If ComboAutoComplete returns True, then it found a match, and lngListIndex will contain the ListIndex of that match.  If ComboAutoComplete returns False, then it did not find a match, so the ListIndex should be -1.
0
 
sirbountyAuthor Commented:
Okay, some of it is working now...but here's where it's not working...
In my 'small' combos - where the first char would not likely be duplicated in the list, it automatically chooses the correct item.
However in my Office Locations combo, If I want to select Windsor, I type "W" and Waltham is displayed, then I type "i" and Iselin, NJ is displayed, then "n", Nashville, TN, etc...

I suppose it's workable in this manner, but I would rather it bring up the first match and then continue on as each subsequent character is typed...is this possible?
0
 
sirbountyAuthor Commented:
Oh, and thanx again for all your help! : )
0
 
AzraSoundCommented:
>>I suppose it's workable in this manner, but I would rather it bring up the first match and then continue on as each subsequent character is typed...is this possible?

That's how it should work.  How are you using it right now?  The way you describe it working is exactly how a combobox behaves when its style is set to DropDown List.
0
 
sirbountyAuthor Commented:
Firstly, style is dropdown combo - I may need to change that, and I think I do, cause I'm not trapping that as a problem right now...good point.

But, when I used Shauli's code from before, it would react this way:

Type in "W" and a highlighted Waltham, MA would be shown, then type "i" and "Windsor" would be displayed - but on second thought, I've recently removed tabstops, so the user can't 'tab' out to select this, so I think your solution is the one that I will use.

Thanx for your efforts AND patience Azra!
0
 
AzraSoundCommented:
>>I may need to change that, and I think I do

Maybe not.  This style essentially means a user cannot type in the combobox.  AutoComplete functions will not work with this style.  However, this style does require a user pick an item from the list.

My code should do the same...matching words using all the letters typed thus far, which is why I ask how you are using it because there may be some changes that need to be made.
0
 
sirbountyAuthor Commented:
Ok - well ultimately (poor planning on my part I suppose) I wouldn't "want" them typing their own item in 'most' of the combos...
So, I should make these all dropdown list styles - would you agree?

And then the one or two that I could allow them to type - leave that at dropdown combo...I'll make the change and see where that takes me.
I'll also go ahead and close this and just post a link to a new Q if I need more help...
0
 
AzraSoundCommented:
>>So, I should make these all dropdown list styles - would you agree?

Yes, that would make it automatic.  However, if you have combos with thousands of items, it can be difficult for a user to scroll and find what they are looking for, in which case an auto complete feature can be of use.
0
 
sirbountyAuthor Commented:
Okay - all but one (because I have different functions for it) are set to style 2...
The most items in a list, would be my office locations - probably only about 90-100.
But this still only seems to allow selection for the first item in the corresponding list of matches (to the first letter in the item)..hope that makes sense...
0
 
AzraSoundCommented:
Can you post the code for that combo that is giving you problems?
0
 
sirbountyAuthor Commented:
Hmm...that's a lot of code...let me try this function on a fresh combo and I'll post the results...
0
 
sirbountyAuthor Commented:
Must be something I'm doing then...Combo1 displays the same results...
 Is it pehaps the way I'm using it?  I 'assumed' that I should set the listindex to lnglistindex...perhaps not?

    If ComboAutoComplete(cboInfo(Index), lngListIndex) = True Then
        cboInfo(Index).ListIndex = lngListIndex
        'lngListIndex contains the current ListIndex of the displayed item
    End If
0
 
AzraSoundCommented:
>>I 'assumed' that I should set the listindex to lnglistindex...perhaps not?

No, you don't need to do that.  The listindex is returned for your benefit only as it may apply to other things.  Otherwise, the function should handle everything else including partial highlighting and selecting the most appopriate item in the list.
0
 
sirbountyAuthor Commented:
So, it should just read:

If ComboAutoComplete(cboInfo(Index), lngListIndex) = True Then
End If

??

My 'dummy' combo has:

Cat
Catastrophe
Catatonic

I can't get to the latter two without 'arrowing' down to them, cause as soon as I hit the 'a', it goes back to Apple...but you're saying it should show the others?
0
 
AzraSoundCommented:
This should work:

Private Sub Combo1_Change()
    Dim lngListIndex As Long
   
    Call ComboAutoComplete(Combo1, lngListIndex)
End Sub

Private Sub Form_Load()
    Combo1.AddItem "Cat"
    Combo1.AddItem "Catastrophe"
    Combo1.AddItem "Catatonic"
End Sub
0
 
sirbountyAuthor Commented:
Okay - it's something else, because I created a new project and it works as it should...
I'm going to open a new question to see if you and/or anyone else can help me track down what's causing this not work... :(
0
 
sirbountyAuthor Commented:
here's another weird thing...for combo1 - if I place a break on combo1_change, and I 'type' in that box, it doesn't stop there....only combo1_click (which I added after)...strange?
0
 
sirbountyAuthor Commented:
AzraSound - would you mind helping me with this again? If you're around...
New program - same routine...can't get it working right.

http:Visual_Basic/Q_21273233.html
0
 
sirbountyAuthor Commented:
Sometimes it just helps to post a question...I've got it...well, sort of - about 95% of the way there...
: )
0
 
AzraSoundCommented:
:-)

I came back from lunch and noticed the question was gone.  Glad to see you got it straightened out.
0
 
sirbountyAuthor Commented:
Well...sort of...
Still one minor issue.  
The new app has similiar two drop-downs for Category & Subcategory.
If a certain Subcat is chosen, a customer dropdown is displayed.
If that dropdown is not displayed, my code sets the focus on the first time-entry (date/time control).
If the customer field is shown, it appears the 'nothing' gets the focus...not sure why.

If I'm still stuck on it tomorrow - I'll post another question for you...thanx for all your help!
0

Featured Post

Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

  • 28
  • 13
  • 4
  • +3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now