Как сделать QComboBox с редактируемым только одним полем?

Я хочу сделать QComboBox, который позволит вам выбрать значение или ввести свое собственное значение. Это должно работать так, что если вы выберете редактируемый параметр и введете текст, это будет текст для этого параметра. Если вы выберете другое, а затем вернетесь к редактируемому, введенный вами текст должен сохраниться.

Я уже добился некоторого прогресса. Это выглядит так:

Меню со списком

описание изображения

Выбран редактируемый элемент

описание изображения

Выбран обычный элемент

описание изображения

Я достиг этого, используя фильтр событий:

class MagicComboBoxEventFilter : public QObject {
public:
    explicit MagicComboBoxEventFilter(QObject* parent=0) : 
          QObject(parent),
          parentBox(nullptr),
          lastValue(""),
          editableIndex(-1)
    {
        parentBox = dynamic_cast<QComboBox*>(parent);
        if(parentBox) {
            connect(parentBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
                this, &MagicComboBoxEventFilter::currentIndexChanged);
    }
public slots:
        void currentIndexChanged(int index) {
            // Item data entry is unused, so I used it to determine
            // the editable field from others
            bool editable = parentBox->itemData(index).toInt()==666;
            parentBox->setEditable(editable);
        }
private:
    QComboBox* parentBox;
};

Это применяется к новому выпадающему списку:

QComboBox* comboBox = new QComboBox(this);
comboBox->setEditable(false);
new MagicComboBoxEventFilter(comboBox);

Проблема, с которой я сталкиваюсь, заключается в том, как сохранить редактируемое значение, даже если пользователь выбирает другие элементы. Я попытался подключиться к событию изменения редактируемого текста, это мой расширенный фильтр событий. Я не буду повторять весь код класса, другое дело, что теперь в конструкторе есть дополнительный вызов connect:

public slots:
        void currentIndexChanged(int index) {
            bool editable = parentBox->itemData(index).toInt()==666;
            parentBox->setEditable(editable);

            // If editable field selected, restore the last value entered
            if(editable) {
                parentBox->setItemText(index, lastValue);
            }
        }
        // slot connected in constructor
        void editTextChanged(const QString& text) {
            lastValue = text;
        }
private:
    QComboBox* parentBox;
    // Last string value the editable field had
    // qt doesn't remember that
    QString lastValue;

Проблема в том, что когда пользователь выбирает другой элемент, editTextChanged срабатывает перед currentIndexChanged, и я получаю текст выбранного элемента в lastValue, а не последний введенный текст.

Как это обойти? Я очень старался, и мне нужна помощь.


person Tomáš Zato - Reinstate Monica    schedule 19.05.2016    source источник
comment
Может быть, получить дочерние элементы QComboBox, который является QStandardItemModel, и установить на него другой фильтр событий? У меня нет времени тестировать ваш код, но ответ на этот вопрос может меня заинтересовать   -  person IAmInPLS    schedule 19.05.2016


Ответы (1)


Хм, я хотел то же самое, но я думаю, что это было довольно просто (извините, синтаксис python):

class EditableComboBox(QComboBox):

    def __init__(self):
        QComboBox.__init__(self)
        self.currentIndexChanged.connect(self.fix)
        self.setInsertPolicy(QComboBox.InsertAtCurrent)

    def fix(self, index):
        if (self.currentData() == '----'):
            self.setEditable(True)
        else:
            self.setEditable(False)

По сути, просто установите insertPolicy в InsertAtCurrent и реагируйте на каждое currentIndexChanged, устанавливая свойство editable. Я использовал ---- в качестве маркера для редактируемого поля и установил элементы:

cb = EditableComboBox()
cb.addItem('', '----')
cb.addItem('One', '1')
cb.addItem('Two', '2')
cb.addItem('Three', '3')

PS. Когда вы меняете текст, вы должны нажать Enter, чтобы он закрепился, иначе, если вы выберете другой элемент, текст будет потерян.

person Jellby    schedule 06.05.2020