1

I've just added an Item-Filter-Feature to a CComboBox derived class called ComboBoxFbp in an old MFC application.

BOOL CComboBoxFbp::OnEditChange()
{
    CString csText;

    if (m_wFbpMode & _FbpMode_UserTextFiltersList) {
        GetWindowText(csText);

        // This makes the DropDown "flicker"
        // ShowDropDown(false);

        // Just insert items that match
        FilterItems(csText);

        // Open DropDown (does nothing if already open)
        ShowDropDown(true);
    }

    return FALSE;   // Notification weiterleiten
}

void CComboBoxFbp::FilterItems(CString csFilterText)
{
    CString csCurText;
    int nCurItem;
    DWORD wCurCursor;

    // Text/selection/cursos restore
    GetWindowText(csCurText);
    nCurItem = GetCurSel();
    if (nCurItem != CB_ERR && nCurItem >= 0 && nCurItem < GetCount()) {
        CString csCurItemText;
        GetLBText(nCurItem, csCurItemText);
        if (csCurItemText == csCurText)     csCurText = csCurItemText;
        else                                nCurItem = CB_ERR;
    } else {
        nCurItem = CB_ERR;
    }

    wCurCursor = GetEditSel();

    // Delete all items
    ResetContent();

    csFilterText.MakeLower();

    // Add just the items (from the vector of all possibles) that fit
    for (auto item : m_vItems)
    {
        CString csItemText = item.first;
        csItemText.MakeLower();
        if (!csFilterText.IsEmpty() && csItemText.Find(csFilterText) < 0)
            continue;

        const int i = AddString(item.first);
        SetItemData(i, item.second);
    }

    // Text/selection/cursos restore
    if (nCurItem != CB_ERR)     SelectString(-1, csCurText);
    else                        SetWindowText(csCurText);
    SetEditSel(LOWORD(wCurCursor), HIWORD(wCurCursor));
}

So when the user types, the long list of items in the DropDown gets filtered accordingly. Everything's fine so far.

The size/height of the ListBox/DropDown doesn't change once its open. It does change accordingly when die DropDown opens. Meaning if there are only 2 items the DropDown is only 2 items high.

My issue

When the user enters a text where just one item fits the DropDown is only 1 item in height (this happens with some user workflows, i.e. user manually closes & opens the DropDown).

Now when the user now changes the text so multiple items are fitting the height stays 1 item and it looks weird as even the scrollbar doesn't look correct as it doesn't fit.

What I've tried so far

  1. I cannot use CComboBox::SetMinVisibleItems (or the MSG behind it) as it only works in a Unicode CharacterSet (which I'm not able to change in this old application) and from WinVista onwards (app runs on WinXP).
  2. The only other option is to close and open the DropDown so it gets redrawn correctly with the correct height (see // This makes the DropDown "flicker" in Source Code above).

Now going with option 2 I don't want the user to see the closing and opening ("flicker") of the DropDown after every key he is pressing.

To prevent this I've tried a couple of solutions I've found but none works in my case with a ComboBox-DropDown. Here's a list of methods I've put just before the ShowDropDown(false) and just after the ShowDropDown(true).

  1. EnableWindow(false/true);
  2. (Un)LockWindowUpdate();
  3. SendMessage(WM_SETREDRAW, FALSE/TRUE, 0)

With all three calls I still see the DropDown closing/opening.

Do you guys have other ideas how I can prevent this flicker?

Thanks in advance Soko

Jabberwocky
  • 48,281
  • 17
  • 65
  • 115
Soko
  • 774
  • 1
  • 7
  • 20
  • 1
    The feature you tried to re-implement is already available. See [Using Autocomplete](https://learn.microsoft.com/en-us/windows/desktop/shell/ac-ovw) and particularly [How to Enable Autocomplete Manually](https://learn.microsoft.com/en-us/windows/desktop/shell/how-to-enable-autocomplete-manually). With that you only have to manage the list of candidates, and let the system do everything else for you. – IInspectable Sep 20 '18 at 07:28
  • I've had a look at that, but the `Autoappend` feature was something I definetly not wanted. I somehow missed the `Autosuggest` mode though... I'd like to give it a try and would welcome some sample code if you're in the mood... – Soko Sep 20 '18 at 09:33

1 Answers1

1

This is an XY question.

It should be easier to use the following approach to adjust the height of the ComboBox

  1. Use GetComboBoxInfo to get the handle of the list control.
  2. Use OnChildNotify or ON_CONTROL_REFLECT and capture CBN_DROPDOWN.
  3. In the handler of the message resize the window as needed Use SetWindowPos and just change the size.
xMRi
  • 14,982
  • 3
  • 26
  • 59
  • Hhhmm... I get what you mean... I think... But this handler/capture of `CBN_DROPDOWN` gets only called when the DropDown opens (afaik). My DropDown is already open (and is only 1 item high) when I add more items. So this wouldn't work if I'm not mistaken... – Soko Sep 20 '18 at 09:39
  • 1
    Just resize the control to a size of 10 or 15 members by default. As you are shrinking and enlarging the contents dynamically this would be an expected behavior for me. – xMRi Sep 20 '18 at 09:41
  • Perhaps you know the number of elements. Resize it first before you add the members. – xMRi Sep 20 '18 at 09:45
  • OK, I see what you mean. Basically never letting the size be smaller than 10/15 items. Even if there are only a couple to display. Right? – Soko Sep 20 '18 at 10:00
  • So you can use SetMinVisibleItems in Vista and later (should also work in the non unicode version), And the resize code must only work in XP. So you can easily cleanup the code when you drop XP (and that should happen soon!) – xMRi Sep 20 '18 at 12:05
  • Nope sorry, I've tried the non-unicode. Once my test project was changed away from unicode the function is not available anymore and even calling the MSG behind it will only return FALSE. Its kinda curious what such a functionality has to do with unicode... – Soko Sep 20 '18 at 14:28
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/180495/discussion-between-soko-and-xmri). – Soko Sep 21 '18 at 06:18