Link to home
Start Free TrialLog in
Avatar of sirbounty
sirbountyFlag for United States of America

asked on

auto complete

See the accepted answer here: https://www.experts-exchange.com/questions/21210092/Autofill-combo-box.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?
Avatar of gary_j
gary_j
Flag of United States of America image

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 ...
Avatar of David Lee
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.
Avatar of sirbounty

ASKER

Hmm - okay, perhaps my problem lies somewhere else....closer look tomorrow (code is at work).
Thanx all
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?
ASKER CERTIFIED SOLUTION
Avatar of AzraSound
AzraSound
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Azra - you mean in place of the other function I was using?  I'll give it a shot...thanx.
AzraSound - am I missing LockWindowUpdate?
Replacing this one for the prior doesn't seem to be working... :(
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
Avatar of Shauli
Shauli

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

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.
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
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
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
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...
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
Hm...I was afraid you'd say that....<sigh>
Okay - hunt and peck game, here I go... :(
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.
Yep - seeing it even when running a full compile... : (
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
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...
Did you try my routine?
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...
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
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... :(
I placed it above.  It needs to be public in a bas module with the rest of your API declarations.
Ok...brb..
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
Hmm...it doesn't seem to be allowing any character input and .text is always = "", thus exiting the function...
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.
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?
Oh, and thanx again for all your help! : )
>>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.
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!
>>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.
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...
>>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.
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...
Can you post the code for that combo that is giving you problems?
Hmm...that's a lot of code...let me try this function on a fresh combo and I'll post the results...
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
>>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.
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?
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
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... :(
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?
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
Sometimes it just helps to post a question...I've got it...well, sort of - about 95% of the way there...
: )
:-)

I came back from lunch and noticed the question was gone.  Glad to see you got it straightened out.
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!