ComboBox — добавить значение пользователя в раскрывающийся список

У меня CComboBox - тип выпадающего списка. Я добавляю туда любые предопределённые значения из своего списка в методе OnInitDilaog(). Пользователь может выбрать значение из списка или добавить свое собственное значение в поле редактирования. Как добавить новое значение пользователя в раскрывающийся список? В идеале, когда он нажимает Enter?

 BOOL CMFCtestDlg::OnInitDialog()
   {
       m_cCombo.AddString(L"Volba 1");
       m_cCombo.AddString(L"Volba 2");

       return TRUE;  
   }

Является ли диалог всплывающим окном? Это может привести к странному поведению пользовательского интерфейса, поскольку кнопка [Ввод] по умолчанию захватывается кнопкой диалогового окна по умолчанию, обычно кнопкой IDOK, которая закрывает диалоговое окно. В MFC это происходит, даже если в вашем диалоге фактически нет кнопки по умолчанию (вызывает член OnOK()), и вам нужно написать код, чтобы предотвратить это. Если вы хотите захватить [Enter], если элемент управления полем со списком находится в фокусе, это возможно, но, пожалуйста, примите во внимание приведенные выше соображения.

Constantine Georgiou 14.07.2024 23:52

Лучшим решением может быть просто избавиться от поля редактирования и вместо этого добавить в список заранее определенный элемент, например «Добавить значение», и, если пользователь выберет его, запросить у него значение и добавить его в список.

Remy Lebeau 15.07.2024 02:12
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
2
80
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Проблема с 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

sergiol 17.07.2024 18:37

Другие вопросы по теме