【问题标题】:How do i make only one QComboBox item editable?如何仅使一个 QComboBox 项目可编辑?
【发布时间】:2019-07-22 13:34:36
【问题描述】:

我的 Qt 应用程序中有QComboBox,我希望它有几个默认的、不可编辑的项目,但我也希望它有一个可编辑的项目,它有默认文本,但一旦编辑和一些确认就会被替换按钮被按下(默认输入)。

这是我尝试过的:

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

这样所有项目都是可编辑的,一旦我编辑任何项目并按 Enter 键,它保持不变,但带有已编辑文本的新项目会插入到框中。

我怎样才能实现我想要的行为?任何帮助表示赞赏!

P.s.我表示我的目标是只有一个可编辑的项目,但我也想知道如何以同样的方式插入无穷无尽的(有条件的)新项目。

【问题讨论】:

    标签: c++ qt qcombobox


    【解决方案1】:

    解决方案是使用模型视图模式进行组合框和子类化QComboBox

    1:实现自定义模型。在我的情况下,我在 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:子类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:使用

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

    【讨论】:

    • 感谢您的回答。不幸的是我有一个问题,我希望你能指出什么是错的。我能够创建MyCombobox 的实例,但是一旦我尝试为其设置任何数据,我的应用程序就会崩溃(包括在MyModel 的实例上使用setModel 方法,如您的答案所示)。知道为什么吗?
    • 1.检查崩溃点:在模型创建或setModel 2. 尝试将另一个模型设置为组合框,如QStandardItemModel 3. 使用组合框的替代创建。如果您使用 GUI 设计器(通过小部件的推广)创建组合框子类 (MyCombobox),则尝试仅在 C++ 端创建。 4. 当然检查你的组合框是否不为空(可能出于某种奇怪的原因)
    • 我可以将QStandardItemModel 设置为MyCombobox,也可以将MyModel 设置为QComboBox,所有这些都不会崩溃。但不幸的是,他们都没有一起工作,这真的很混乱
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-11-14
    • 2018-06-06
    • 1970-01-01
    • 1970-01-01
    • 2023-03-23
    • 2019-11-05
    • 2019-03-13
    相关资源
    最近更新 更多