views:

35

answers:

3

I have a form in Excel with a combo box control. I want the values to be filled from a database table when the combo box is opened using what has already been typed in as a LIKE criteria. This is the code I have so far for the DropButtonClick event to achieve this.

Private Sub cboVariety_DropButtonClick()
    Static search_text As String
    Static is_open As Boolean
    Dim rs As New Recordset

    If is_open Then
        is_open = False
        Exit Sub
    End If
    is_open = True

    If search_text = cboVariety Then Exit Sub
    search_text = cboVariety

    cboVariety.Clear
    cboVariety.AddItem search_text
    If Len(search_text) > 2 Then
        rs.Open _
            "SELECT Name FROM tbl_Varieties " & _
            "WHERE Name LIKE '%" & search_text & "%' " & _
            "ORDER BY Name", connect_string, adOpenStatic
        Do Until rs.EOF
            If rs!Name <> search_text Then cboVariety.AddItem rs!Name
            rs.MoveNext
        Loop
        rs.Close
    End If
End Sub

The problem is that the DropButtonClick event fires both when the combo box is opened and when it is closed. If this sub executes when the combo box is closing, the code that clears the combo box causes the user's selection to be erased.

I'm trying to tell when the box is closed using the is_open variable, which alternates between true and false each time the event sub is executed. This seems like a brittle solution to the problem. Is there a better way?

A: 

Use GotFocus() instead.

 Private Sub ComboBox1_GotFocus()
    MsgBox "caca"
 End Sub

Triggers only when the combo get focus.

HTH

belisarius
GotFocus is a .NET event, I think... Excel uses much (, much) older controls. The equivalent VBA control event is Enter, but the problem is that the search criteria will be typed in after the control gets focus, so I really need the event to be handled right before the combo box is opened.
Tmdean
+1  A: 

You are on the right track by using the is_open boolean to track the state of the combo box, but what you really want to track is the state of "should I re-populate the combo box with database data?"

When do you want the list box populated? Currently, you want the list box to be populated every time the user clicks the drop-down box (not taking into account your is_open state variable). Is this really what you want?

I would imagine that what you really want is to have the combo box only update after something else changes. Perhaps you only want the drop down list to update when the form first opens. Maybe you only want the data to change when the text in a search box changes. If this is the case, you need to base your logic on the state of when you actually want to perform the update.

For example, let's say you want to update the combo box only if the text in a search box changes. I'm not looking at Excel at the moment, but let's pretend you have a text box called txtSearch with a Text property. I'd start by adding a module or class level variable to maintain the state of the previous text entry:

Private mPreviousSearchText As String

Then I'd update my event code like so:

Private Sub cboVariety_DropButtonClick()                                      
    Dim rs As New Recordset                    
    Dim search_text As String

              search_text = txtSearch.Text

    If mPreviousSearchText = search_text Then                      
       'The current search matches the previous search,'
       'so we do not need to perform the update.'
        Exit Sub                    
    End If                                                    

    cboVariety.Clear                    
    cboVariety.AddItem search_text                    
    If Len(search_text) > 2 Then                    
        rs.Open _                    
            "SELECT Name FROM tbl_Varieties " & _
            "WHERE Name LIKE '%" & search_text & "%' " & _
            "ORDER BY Name", connect_string, adOpenStatic
        Do Until rs.EOF                    
            If rs!Name <> search_text Then cboVariety.AddItem rs!Name
            rs.MoveNext                    
        Loop                    
        rs.Close                                
    End If             
    'Set the previousSearchText var to be the search_text so that it does'
    'not run unless the value of my text box changes.'
    mPreviousSearchText = search_text 
End Sub

The entire point is to establish when you actually want to perform the update and find out a way to tie your logic decision to the state associated with when you want to perform the action, which is only coincidentally related to the user clicking on the drop-down box.

Ben McCormack
Very good point, but actually I'm already using this logic in my code. search_text is a static variable and my sub bails out right away if search_text hasn't changed between calls.
Tmdean
The search box and combo box are the same thing - the search criteria is typed into the combo box, then when it's opened it populates from the table. The problem is that if you pick an item from the drop down list, then the combo box value changes, so when the event procedure runs again, it doesn't bail out and the list item that was picked is discarded.
Tmdean
@Tmdean Ok, now I see the problem you are having. You are using the same combo box to both provide the data for the query and serve as the target for the updated list? I see why you have a problem. Since the process is going to require multiple clicks anyway, you might consider moving the functionality to two different controls: one to provide the search input and another to provide the list of items. That way you can better manage the state of when you need to perform the update. Since the user already has to click, it doesn't seem like much of a compromise.
Ben McCormack
+1  A: 

I found a simple way to solve this. It doesn't seem like it should work, but if I just reassign the value of the combo box after rebuilding the list, it doesn't discard the value that is selected.

Private Sub cboVariety_DropButtonClick()
    Static search_text As String
    Dim rs As New Recordset

    If search_text = cboVariety Then Exit Sub
    search_text = cboVariety

    cboVariety.Clear
    If Len(search_text) > 2 Then
        rs.Open _
            "SELECT Name FROM tbl_Varieties " & _
            "WHERE Name LIKE '%" & search_text & "%' " & _
            "ORDER BY Name", connect_string, adOpenStatic
        Do Until rs.EOF
            cboVariety.AddItem rs!Name
            rs.MoveNext
        Loop
        rs.Close
    End If

    '' Reassign cboVariety in case this event was triggered by combo close
    cboVariety = search_text
End Sub
Tmdean
@Tmdean Ths only problem you could possible experience is that the value the user selected isn't returned from the query, but that should never happen, right?
Ben McCormack
Actually it should happen, if they search for something that isn't there, but it's legal to assign a value to a combo box that doesn't exist in the drop down list.
Tmdean