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
- 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). - 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)
.
- EnableWindow(false/true);
- (Un)LockWindowUpdate();
- 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
This is an XY question.
It should be easier to use the following approach to adjust the height of the ComboBox
GetComboBoxInfo
to get the handle of the list control.OnChildNotify
orON_CONTROL_REFLECT
and captureCBN_DROPDOWN
.SetWindowPos
and just change the size.