MFC/C++ ComboBox: отключить рисование закрытия и открытия Dropdown (заморозка пользовательского интерфейса)
Я только что добавил Item-Filter-Feature к CComboBox
производный класс называется ComboBoxFbp
в старом приложении MFC.
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));
}
Поэтому, когда пользователь печатает, длинный список элементов в DropDown фильтруется соответствующим образом. Пока все хорошо.
Размер / высота ListBox/DropDown не изменяется после его открытия. Это меняется соответственно, когда открывается DropDown. Это означает, что если есть только 2 предмета, то DropDown имеет высоту только 2 предмета.
Моя проблема
Когда пользователь вводит текст, в который помещается только один элемент, DropDown имеет высоту только 1 элемента (это происходит с некоторыми рабочими процессами пользователя, т.е. пользователь вручную закрывает и открывает DropDown).
Теперь, когда пользователь изменяет текст так, чтобы подгонять несколько элементов, высота остается на 1 элемент, и это выглядит странно, поскольку даже полоса прокрутки выглядит неправильно, поскольку она не помещается.
Что я пробовал до сих пор
- Я не могу использовать
CComboBox::SetMinVisibleItems
(или MSG за ним), так как он работает только в Unicode CharacterSet (который я не могу изменить в этом старом приложении) и начиная с WinVista (приложение работает на WinXP). - Единственный другой вариант - закрыть и открыть DropDown, чтобы он правильно перерисовывался с правильной высотой (см. // Это делает DropDown "мерцающим" в исходном коде выше).
Теперь перейдя к варианту 2, я не хочу, чтобы пользователь видел закрытие и открывание ("мерцание") DropDown после каждой нажатой клавиши.
Чтобы предотвратить это, я попробовал пару решений, которые нашел, но ни одно из них не работает в моем случае с ComboBox-DropDown. Вот список методов, которые я поставил перед ShowDropDown(false)
и сразу после ShowDropDown(true)
,
- EnableWindow(ложь / истина);
- (Un) LockWindowUpdate ();
- SendMessage (WM_SETREDRAW, FALSE / TRUE, 0)
Со всеми тремя вызовами я все еще вижу закрытие / открытие DropDown.
У вас есть другие идеи, как я могу предотвратить это мерцание?
Заранее спасибо Soko
1 ответ
Это вопрос XY.
Должно быть проще использовать следующий подход для регулировки высоты ComboBox
- использование
GetComboBoxInfo
чтобы получить ручку управления списком. - использование
OnChildNotify
или жеON_CONTROL_REFLECT
и захватитьCBN_DROPDOWN
, - В обработчике сообщения измените размер окна по мере необходимости.
SetWindowPos
и просто измените размер.