Go to the list item by entering the first few characters

I have a list of elements (potentially large) from which the user must select one. I would like to allow the user to enter the first few letters of the desired item in order to go to the right place in the list. By default, each keystroke jumps to the first element starting with this letter, so you cannot enter the first few letters. Is there an easy way to do this? Any CodeProject or other such example?

I looked for a watch and found any number of samples for IAutocomplete, but this will not help, because I have to guarantee that the result will be in the list.

The only way I can do this is to exit the CListBox, grab the keystrokes myself, find the item, start the timer so that new keystrokes after a sufficient pause will start a new search ... since I'm not an MFC jock, it's complicated. Any advice is greatly appreciated.

One clarifying note: my ultimate goal is actually to get this keyboard behavior for a ComboBox of the DropDownList style (i.e. without an edit box). The absence of an editing field eliminates most autocomplete codes, and the need for ComboBox functionality means that I cannot use CListCtrl myself.

+5
source share
3 answers

, - LBS_SORT. , , , . LBS_SORT ( CBS_SORT combobox) . LBS_SORT, .

, .. - , Microsoft LBS_SORT!!

, .

+10

​​ Win32. .

- , :

 switch(message)
{   
   case WM_CHAR:       
    if(HandleListBoxKeyStrokes(hwnd, wParam) == FALSE)
                return FALSE;

....

(, ):

/* ======================================================================== */
/* ======================================================================== */
#define RETURNr(a, b) // homegrown asserts

BOOLEAN HandleListBoxKeyStrokes(HWND hwnd, UINT theKey)   

{
    #define MAXCHARCACHEINTERVALL 600.0  // Max. milisecs time offset to consider as typed 'at once'
    static char sgLastChars[255] = {'0'};
    static double  sgLastCharTime = 0.;

static HWND    sgLasthwnd = NULL;


if(GetSecs() - sgLastCharTime > MAXCHARCACHEINTERVALL ||
    sgLasthwnd != hwnd) 
    *sgLastChars = 0;

if(theKey == ' ' && *sgLastChars == 0)
    return TRUE; 

sgLastCharTime = GetSecs();
sgLasthwnd = hwnd; 

AppendChar(sgLastChars, toupper(theKey));

if(strlen(sgLastChars) > 1)
{
        LONG l = GetWindowLong(hwnd, GWL_STYLE);
        Char255 tx;
        GetClassName(hwnd, tx, sizeof(tx));
        if(  (! stricmp(tx, "Listbox") && 
              ! (l & (LBS_EXTENDEDSEL | LBS_MULTIPLESEL)) ) ||
             (! stricmp(tx, "ComboBox") &&  // combo Box support
                 l & CBS_DROPDOWNLIST   &&
              ! (l & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) ) )
        {
            long Count, l, BestMatch = - 1, BestMatchOff = 0;
            long LBcmdSet[] = {LB_GETCOUNT, LB_GETTEXTLEN  , LB_GETTEXT};
            long CBcmdSet[] = {CB_GETCOUNT, CB_GETLBTEXTLEN, CB_GETLBTEXT};
            long *cmdSet = (! stricmp(tx, "ComboBox")) ? CBcmdSet : LBcmdSet;

            RETURNr((Count = SendMessage(hwnd, cmdSet[0], 0, 0)) != LB_ERR, 0);
            for(int i = 0; i < Count; i++)


         {
                    RETURNr((l = SendMessage(hwnd, cmdSet[1], i, 0)) != LB_ERR, TRUE);
                    RETURNr( l < sizeof(tx), TRUE);
                    RETURNr((l = SendMessage(hwnd, cmdSet[2], i, (LPARAM)&tx)) != LB_ERR, TRUE);
                    strupr(tx);
                    if(! strncmp(tx, sgLastChars, strlen(sgLastChars)))
                    {
                        SelListBoxAndNotify(hwnd, i);
                        return FALSE;
                    }
                    char *p;
                    if(p = strstr(tx, sgLastChars))
                    {
                        int off = p - tx;
                        if(BestMatch == -1 || off < BestMatchOff)
                        {
                           BestMatch = i;
                           BestMatchOff = off;
                        }
                    }
                }
                // If text not found at start of string see if it matches some part inside the string
                if(BestMatch != -1)
                        SelListBoxAndNotify(hwnd, BestMatch);
                // Nothing found - dont process
                return FALSE;
            }
        }
        return TRUE;
    }
    /* ======================================================================== */
    /* ======================================================================== */

    void SelListBoxAndNotify(HWND hwnd, int index)

    {
    // i am sorry here - this is some XVT-toolkit specific code.
    // it has to be replaced with something similar for native Win32
        WINDOW win    = xvtwi_hwnd_to_window(hwnd);
        WINDOW parent = xvt_vobj_get_parent(win);
        xvt_list_set_sel(win, index, 1);
        EVENT evt;
        memset(&evt, 0, sizeof(evt));
        evt.type = E_CONTROL;
        evt.v.ctl.id = GetDlgCtrlID(hwnd);
        evt.v.ctl.ci.v.lbox.dbl_click = FALSE;
        xvt_win_dispatch_event(parent, &evt);  
    }
    /* ======================================================================== */
    /* ======================================================================== */

double  GetSecs(void)

{
        struct timeb timebuffer;
        ftime(&timebuffer);
        return (double)timebuffer.millitm + 
              ((double)timebuffer.time * 1000.) - // Timezone needed for DbfGetToday
              ((double)timebuffer.timezone * 60. * 1000.);
}
    /* ======================================================================== */
    /* ======================================================================== */

char    AppendChar(char *tx, char C)

{       int i;

        i = strlen(tx);
        tx[i    ] = C;
        tx[i + 1] = 0;
        return(C);
}
+3

Can you use instead? They work by default. CListView CListCtrl

+1
source

All Articles