How to Build a Custom Combo Box

Last reviewed: January 10, 1997
Article ID: Q155013
The information in this article applies to:
  • Microsoft Visual FoxPro for Windows, versions 3.0, 3.0b

SUMMARY

When using a large table or cursor (over 500 records) as the RowSource for a Combo Box, you may start to see a slow down in the Combo Box performance. This article shows how to create a control that has the basic Combo Box functionality but does not have the same performance slow down that the standard Combo Box has when working with a large table.

MORE INFORMATION

The fastest control for working with a large number of records is the Grid. However, there are times when there is not enough space on a form for a grid or when the developer needs the functionality of a Combo Box but without the performance overhead that the standard Combo Box has. The following example shows how to create a custom Combo Box using a Grid, Text Box, and Command Button. If you are not familiar with creating or using visual classes, please see chapter 10 of the Microsoft Visual FoxPro Developer's Guide.

Step-by-Step Example

  1. Create a new class named NewPopup based on a Container, and save it in Mylib.

  2. Add the following new properties and methods to the NewPopup container:

    cSearchString as a Property tOutTime as a Property Pop as a Method Search as a Method

  3. Set the following properties for the NewPopup container:

    Width = 128 Height = 185 BackStyle = 0 BorderWidth = 0 tOutTime = .NULL.

  4. Add a Text Box to the container and set the following properties:

    Height = 26 Left = 2 ReadOnly = .T. && If you want to be able to edit the data in

                      ** the text box leave this property set to .F.
       Top = 2
       Width = 111
    
    

  5. Enter the following code in the KeyPress Event for Text1:

    IF nKeyCode = 160

          This.Parent.Command1.Click()
          ** Makes the grid appear when you press the ALT+DOWNARROW key
    
    ENDIF

  6. Add a Command Button to the container and set the following properties:

    Top = 2 Left = 112 Height = 26 Width = 13 FontBold = .F. FontName = Wingdings FontSize = 6 Caption = ALT + 0234 ** When you hold down the ALT key and press the NUMBER keys, it ** inserts a down arrow character for the Caption

  7. Enter the following code in the Click Event for Command1:

    This.Parent.Grid1.Visible = .T. && Make the Grid visible This.Parent.Zorder(0) ** Places the container in front of other objects This.Parent.Grid1.Column1.Text1.SetFocus IF !ISNULL(This.Parent.tOutTime)

         KEYBOARD '{Enter}'
         ** Forces the Grid to Activate
         ** Without this, the grid would not work properly when you
         ** enter it the second time.
    
    ENDIF

  8. Add a Grid to the container and set the following properties:

    ColumnCount = 1 DeleteMark = .F. GridLines = 0 GridLineWidth = 0 HeaderHeight = 0 Height = 156 Left = 2 MousePointer = 1 ReadOnly = .F. RecordMark = .F. ScrollBars = 2 Top = 27 Visible = .F. Width = 123

  9. Enter the following code in the AfterRowColChange Event of Grid1:

    This.Parent.Text1.Value = This.Column1.Text1.Value

  10. Set the following properties for Column1 in Grid1:

        Width = 124
        Sparse = .F.
    

  11. Set the following properties for Text1 in Column1 of Grid1:

        BorderStyle = 0
        Format = K
        HideSelection = .F.
        MousePointer = 1
        SpecialEffect = 1
    

  12. Enter the following code in the Click Event of Text1 in Column1 of

        Grid1:
    

        This.Parent.Parent.Parent.Pop()
    

  13. Enter the following code in the KeyPress Event of Text1 in Column1 of

        Grid1:
    

        IF nKeyCode = 13  && Then hit the ENTER key
           This.Parent.Parent.Parent.Pop()
        ENDIF
        IF (nKeyCode > 48 AND nKeyCode < 58) OR ;
           (nKeyCode > 64 AND nKeyCode < 123)
           ** Calls the search method if you hit a letter or numeric key
           This.Parent.Parent.Parent.Search(nKeyCode)
        ENDIF
    

  14. Enter the following code in the GotFocus Event of the NewPopup

        Container:
    

        SET BELL OFF
    

  15. Enter the following code in the Init Event of the NewPopUp Container:

        This.Grid1.HeaderHeight = 0
        ** When you modify an instance of the class in a Form and modify
        ** some of the grid setting, it will change the HeaderHeight property
        ** back to a default size. This line of code will set the
        ** HeaderHeight back to 0 at run time
        This.Zorder(1)
        ** Moves the container behind any controls that it may be on top of
        nFieldlen = FSIZE(This.Grid1.Column1.ControlSource)
        ** resize the grid based on the field size and font
        IF This.Width < (nFieldlen * ;
           FONTMETRIC(6,This.Grid1.FontName,This.Grid1.FontSize,"B"))+12
    

           This.Width = (nFieldlen * ;
    
             FONTMETRIC(6,This.Grid1.FontName,This.Grid1.FontSize,"B"))+12
    
           This.Grid1.Width = (nFieldlen * ;
             FONTMETRIC(6,This.Grid1.FontName,This.Grid1.FontSize,"B"))+10
    
           This.Grid1.Column1.Width = (nFieldlen * ;
             FONTMETRIC(6,This.Grid1.FontName,This.Grid1.FontSize,"B"))
        ENDIF
    
    

  16. Enter the following code in the LostFocus Event of the NewPopUp

        Container:
    

        SET BELL ON
        This.Grid1.Visible = .F.
        This.ZOrder(1)
        ** Moves the container behind any object it is over
    

  17. Enter the following code in the Pop Method of the NewPopUp

        Container:
    

        This.Text1.SetFocus
        This.Grid1.Visible = .F.
        This.ZOrder(1)
        ** Moves the container behind any object it is over
    

  18. Enter the following code in the Search Method of the NewPopUp

        Container:
    

        **Does an incremental search of the table in the grid
        LPARAMETERS nKeyPress
        cField = This.Grid1.Column1.ControlSource
        nRecord=RECNO()
        tInTime = DateTime()
        IF !ISNULL(This.tOutTime)
    

          IF (tInTime - This.tOutTime)<= 1
           This.cSearchString = This.cSearchString + CHR(nKeyPress)
    
            LOCATE FOR UPPER(LEFT(&cField,LEN(This.cSearchString))) = ;
              UPPER(This.cSearchString)
          ELSE
            This.cSearchString=""
            This.cSearchString = CHR(nKeyPress)
            LOCATE FOR UPPER(LEFT(&cField,1)) = UPPER(This.cSearchString)
          ENDIF
    
          IF FOUND()
            This.Grid1.Refresh()
          ELSE
            GO nRecord
            This.Grid1.Refresh()
          ENDIF
    
        ELSE
    
          This.cSearchString=""
          This.cSearchString = CHR(nKeyPress)
          LOCATE FOR UPPER(LEFT(&cField,1)) = UPPER(This.cSearchString)
    
          IF FOUND()
            This.Grid1.Refresh()
          ELSE
            GO nRecord
            This.Grid1.Refresh()
          ENDIF
    
        ENDIF
        This.tOutTime = DateTime()
    
    

  19. Save and close the class.

  20. Create a form and add the NewPopUp container to the form.

  21. Set the RowSource of the Grid1 in the NewPopUp container to the table

        of your choice.
    

  22. Set the ControlSource of Column1 of Grid1 in the NewPopUp container.

  23. Save and run the Form. Click the Command Button to display the Grid,

        and then type the first letter of something you wish to find. Make a
        selection by either clicking on your choice or using the ARROW key
        to highlight your choice and then pressing the ENTER key. You will see
        the Grid disappear and the value of your choice appear in the text box.
    


KBCategory: kbprg kbhowto
KBSubcategory: FxprgClassoop
Additional reference words: 3.00 3.00b kbdsd VFoxWin combobox



THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY.

Last reviewed: January 10, 1997
© 1998 Microsoft Corporation. All rights reserved. Terms of Use.