简体   繁体   English

如何仅使一个QComboBox项目可编辑?

[英]How do i make only one QComboBox item editable?

I have QComboBox in my Qt application and i want it to have few default, non-editable items, but i also want it to have one editable item, which has default text, but is replaced once edited and some confirmation button is pressed (enter, by default). 我在Qt应用程序中有QComboBox ,我希望它具有很少的默认,不可编辑的项目,但是我也希望它具有一个可编辑的项目,该项目具有默认的文本,但是一旦被编辑并按了一些确认按钮就被替换了(输入, 默认)。

Here's what i've tried: 这是我尝试过的:

QComboBox* combo_1 = new QComboBox();
combo_1->setEditable(true);
combo_1->addItems(QStringList()<<"Option_1."<<"Option_2."<<"Option_3."<<"Option_4."<<"Other...");

This way all the items are editable and once i edit any item and press enter, it stays the same, but new item with edited text is inserted to the box. 这样,所有项目都是可编辑的,一旦我编辑了任何项目并按Enter,它便保持不变,但是具有已编辑文本的新项目会插入框中。

How can i achieve the behaviour i want? 我该如何实现自己想要的行为? Any help is appreciated! 任何帮助表示赞赏!

Ps i indicated my goal as to have only one editable item, but i'd also like to know how to insert endless(conditionally) amount of new items the same way. 附言:我的目标是只拥有一个可编辑的项目,但我也想知道如何以相同的方式插入无数(有条件)新项目。

Solution is using model-view pattern for combobox and subclassing QComboBox . 解决方案是将模型视图模式用于组合框并子类化QComboBox

1 : Implement custom model. 1 :实现自定义模型。 In my case I have editable item in row = 2 ( QString m_strEditableValue ) and fixed items in 0,1 rows. 在我的情况下,我在row = 2( QString m_strEditableValue )中有可编辑的项目,在0.1行中有固定的项目。

class MyModel : public QAbstractItemModel
{
    Q_OBJECT
public:
    explicit MyModel(QObject *parent = nullptr);

    QModelIndex index(int row, int column, const QModelIndex &parent) const;
    QModelIndex parent(const QModelIndex &child) const;
    int rowCount(const QModelIndex &parent) const;
    int columnCount(const QModelIndex &parent) const;
    QVariant data(const QModelIndex &index, int role) const;
    bool setData(const QModelIndex &index, const QVariant &value, int role);
    Qt::ItemFlags flags(const QModelIndex &index) const;

private:
    QString m_strEditableValue;

};

MyModel::MyModel(QObject *parent) : QAbstractItemModel(parent)
{
    m_strEditableValue = "default value";
}

QModelIndex MyModel::index(int row, int column, const QModelIndex &parent) const
{
    return createIndex(row, column);
}

QModelIndex MyModel::parent(const QModelIndex &child) const
{
    return QModelIndex();
}

int MyModel::rowCount(const QModelIndex &parent) const
{
    return 3;
}

int MyModel::columnCount(const QModelIndex &parent) const
{
    return 1;
}

QVariant MyModel::data(const QModelIndex &index, int role) const
{
    if (role == Qt::DisplayRole || role == Qt::EditRole)
    {
        if (index.row() == 0) {
            return tr("First fixed value");
        }
        if (index.row() == 1) {
            return tr("Second fixed value");
        }

        if (index.row() == 2) {
            return m_strEditableValue;
        }
    }

    return QVariant();
}

bool MyModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if (role == Qt::EditRole) {
        if (index.row() == 2) {
            m_strEditableValue = value.toString();
            return true;
        }
    }

    return false;
}

Qt::ItemFlags MyModel::flags(const QModelIndex &index) const
{
    Qt::ItemFlags f = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
    if (index.row() == 2) {
        //mark editable only for row 2
        f = f | Qt::ItemIsEditable;
    }
    return f;
}

2 : Subclass QComboBox to change standard behavior 2 :子类QComboBox更改标准行为

class MyCombobox : public QComboBox
{
    Q_OBJECT
public:
    explicit MyCombobox(QWidget *parent = nullptr);

private slots:
    void OnEditTextChanged(const QString& text);
    void OnCurrentIndexChanged(int index);

public slots:
};

MyCombobox::MyCombobox(QWidget *parent) : QComboBox(parent)
{
    connect(this, &QComboBox::editTextChanged, this, &MyCombobox::OnEditTextChanged);
    connect(this, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &MyCombobox::OnCurrentIndexChanged);
}

void MyCombobox::OnEditTextChanged(const QString &text)
{
    if (model()) {
        //set data to model immediately 
        model()->setData(model()->index(currentIndex(), 0), text);
    }
}

void MyCombobox::OnCurrentIndexChanged(int index)
{
    if (model())
    {
        //disable editing if model disable it
        Qt::ItemFlags flags = model()->flags(model()->index(index, 0));
        if (flags & Qt::ItemIsEditable) {
            lineEdit()->setReadOnly(false);
        } else {
            lineEdit()->setReadOnly(true);
        }
    }
}

3 : Using 3 :使用

MyModel *cbModel = new MyModel(this);
ui->cbEditable->setModel(cbModel);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM