У меня CComboBox
- тип выпадающего списка. Я добавляю туда любые предопределённые значения из своего списка в методе OnInitDilaog()
.
Пользователь может выбрать значение из списка или добавить свое собственное значение в поле редактирования. Как добавить новое значение пользователя в раскрывающийся список? В идеале, когда он нажимает Enter?
BOOL CMFCtestDlg::OnInitDialog()
{
m_cCombo.AddString(L"Volba 1");
m_cCombo.AddString(L"Volba 2");
return TRUE;
}
Лучшим решением может быть просто избавиться от поля редактирования и вместо этого добавить в список заранее определенный элемент, например «Добавить значение», и, если пользователь выберет его, запросить у него значение и добавить его в список.
Проблема с Win32 Combo-Box заключается в том, что он не добавляет автоматически содержимое поля редактирования в список и не отправляет уведомление при нажатии клавиши Enter. Итак, нам нужно уловить ключевое событие, то есть обработать его сообщения. В MFC мы можем использовать функцию PreTranslateMessage(). Его часто используют как «последнее средство», но в данном случае оно оказывается очень полезным. Дескриптор поля редактирования можно получить, вызвав функцию Win32/MFC GetComboBoxInfo()
(или отправив сообщение CB_GETCOMBOBOXINFO
).
Выполните следующие шаги:
В классе диалога добавьте член HWND
для хранения дескриптора поля редактирования:
private:
HWND hWCBEdit = NULL; // Combo-box's edit-control
Добавьте несколько строк кода в элемент OnInitDialog()
диалога:
BOOL CMFCtestDlg::OnInitDialog()
{
// Do not delete this, it binds member variables to controls, among others!
CDialogEx::OnInitDialog();
// Get and store CB's edit-control
COMBOBOXINFO cbi { sizeof(COMBOBOXINFO) };
m_cCombo.GetComboBoxInfo(&cbi);
hWCBEdit = cbi.hwndItem;
m_cCombo.AddString(L"Volba 1");
m_cCombo.AddString(L"Volba 2");
return TRUE;
}
Переопределите член PreTranslateMessage()
диалога, как показано ниже:
BOOL CMFCtestDlg::PreTranslateMessage(MSG* pMsg)
{
// Capture [Enter] key for the CB Edit-Box
if (pMsg->message == WM_KEYDOWN && pMsg->hwnd == hWCBEdit && pMsg->wParam == VK_RETURN)
{
TCHAR sCBEdit[100];
if (::GetWindowText(hWCBEdit, sCBEdit, 100) > 0) // CB Edit-Box non-empty
{
if (m_cCombo.FindStringExact(-1, sCBEdit) < 0) // String not in the drop-list
m_cCombo.AddString(sCBEdit);
// Maybe Add some more actions here
}
return TRUE; // Message processed, no further processing is needed
}
return CDialogEx::PreTranslateMessage(pMsg);
}
Это добавит содержимое элемента управления редактированием в список, если нажата клавиша Enter. Диалоговое окно НЕ закроется, если нажать Enter, когда элемент управления редактированием находится в фокусе.
Альтернативным решением, не использующим PreTranslateMessage()
, может быть создание подкласса элемента управления редактированием. Это делается путем изменения его оконной процедуры (проверьте, была ли нажата Enter, в противном случае вызовите исходную).
IIRC, вам не нужно опускаться на такой низкий уровень, чтобы делать эти вещи. Если вы поместите DLGC_WANTALLKEYS
в свойства комбобокса и обработаете его с помощью OnKeyDown
/ OnKeyPress
/ OnKeyUp
, а если нет, вы можете заставить его работать с GetDlgCode
и добиться того же результата. @IInspectable
Является ли диалог всплывающим окном? Это может привести к странному поведению пользовательского интерфейса, поскольку кнопка [Ввод] по умолчанию захватывается кнопкой диалогового окна по умолчанию, обычно кнопкой
IDOK
, которая закрывает диалоговое окно. В MFC это происходит, даже если в вашем диалоге фактически нет кнопки по умолчанию (вызывает членOnOK()
), и вам нужно написать код, чтобы предотвратить это. Если вы хотите захватить [Enter], если элемент управления полем со списком находится в фокусе, это возможно, но, пожалуйста, примите во внимание приведенные выше соображения.