数据更改时如何强制模型更新 QComboBox?

How to force a model to update QComboBox when data changed?

我为 QComboBox 创建了模型:

#ifndef QCOMBOBOXMODEL_H
#define QCOMBOBOXMODEL_H

#include <QModelIndex>


class QComboBoxModel : public QAbstractListModel
{
public:
    QComboBoxModel(QObject *parent=nullptr);
    int rowCount(const QModelIndex &) const;
    QVariant data(const QModelIndex &index, int role) const;
    void populate(const QList<QPair<int,QString>> &values);

private:
    QList<QPair<int,QString>> values;
};

#endif // QCOMBOBOXMODEL_H

代码

#include "qcomboboxmodel.h"

#include <QModelIndex>

QComboBoxModel::QComboBoxModel(QObject *parent)
    :QAbstractListModel(parent)
{
}

int QComboBoxModel::rowCount(const QModelIndex &) const
{
    return values.count();
}


QVariant QComboBoxModel::data( const QModelIndex &index, int role ) const
{        

    QVariant value;

        switch ( role )
        {
            case Qt::DisplayRole: //string
            {
                value = this->values.value(index.row()).second;
            }
            break;

            case Qt::UserRole: //data
            {
            value = this->values.value(index.row()).first;
            }
            break;

            default:
                break;
        }

    return value;
}

void QComboBoxModel::populate(const QList<QPair<int,QString>> &values)
{
    this->values = values;
}

现在我在用它

    values.append(QPair<int,QString>(-1,"Select item"));
    values.append(QPair<int,QString>(10,"item1(0)"));
    values.append(QPair<int,QString>(11,"item1(1)"));
    values.append(QPair<int,QString>(21,"item1(2)"));
    values.append(QPair<int,QString>(32,"item1(3)"));
    values.append(QPair<int,QString>(44,"item1(4)"));

    newidx = 50;


    model = new QComboBoxModel();
    model->populate(values);
    this->ui->comboBox->setModel(model);

然后单击按钮,我将新项目添加到组合框

newidx++;
QString strIdx = QString().number(newidx);
values.append(QPair<int,QString>(newidx,"New item("+strIdx+")"));

model = new QComboBoxModel();
model->populate(values);
this->ui->comboBox->setModel(model);

一切看起来都很好,但这里的问题是我每次向组合框数据添加新项目时都需要重新创建模型

model = new QComboBoxModel();
model->populate(values);
this->ui->comboBox->setModel(model);

这样做合适吗?或者还有另一种方法可以在数据更新时强制更新模型组合框?

为什么不通过 QComboBox 中的“QAbstractItemModel * model() const”请求当前模型;改变它并再次分配它(通过“void QComboBox::setModel(QAbstractItemModel *model)”)?

根据文档中的“模型子类化参考”,您必须做更多的事情才能制作可编辑的模型。为什么您不使用像 QStandardItemModel 这样的现成模型?

    comboModel = new QStandardItemModel(0, 2, this);
    ui->comboBox1->setModel(comboModel);
    comboModel->insertRow(0);
    comboModel->setData(comboModel->index(0, 0), -1);
    comboModel->setData(comboModel->index(0, 1), "Select item");
        //and so on
    //and the data is available as
    int number = comboModel->data(comboModel->index(0, 0)).toInt();
    QString itemtext = comboModel->data(comboModel->index(0, 1)).toString();

我找到解决办法了!

首先我向模型添加新方法

void QComboBoxModel::append(int index, QString value)
{

    int newRow = this->values.count();

    this->beginInsertRows(QModelIndex(), newRow, newRow);

        values.append(QPair<int,QString>(index,value));

    endInsertRows();
}

现在按钮点击方法更改为这个

void MainWindow::on_pushButton_clicked()
{
    qDebug() << "Clicked!";

    newidx++;
    QString strIdx = QString().number(newidx);

    model->append(newidx,"new item " + strIdx );
}

要点是使用 beginInsertRowsendInsertRows 通知模型数据实际发生了变化!

现在一切都按预期工作了!

现在您还可以修改 append 方法以向其中批量添加行,但我认为如果您添加很多行,最好重新创建模型并将其重新分配给组合框。

更新 1:

另外请记住,您在模型内部更新 values QList,因此如果您添加

qDebug() << values;

on_pushButton_clicked()方法中,你总是看到

(QPair(-1,"Select item"), QPair(10,"item1(0)"), QPair(11,"item1(1)"), QPair(21,"item1(2)"), QPair(32,"item1(3)"), QPair(44,"item1(4)"))

更新二:

我也更新了populate方法

void QComboBoxModel::populate(const QList<QPair<int,QString>> &newValues)
{
    int oldIdx = this->values.count();
    int newIdx = newValues.count();
    this->beginInsertRows(QModelIndex(), oldIdx, newIdx);
        this->values = newValues;
    endInsertRows();
}

现在您可以使用 values 列表

void MainWindow::on_pushButton_clicked()
{
    qDebug() << "Clicked!";

    newidx++;
    QString strIdx = QString().number(newidx);

    values.append(QPair<int,QString>(newidx,"new item " + strIdx));
    model->populate(values);

    qDebug() << values;
}

更新 3:

现在,我发现一个大问题 - 我没有在模型内部使用指针,所以当我将 QList 传递给模型时,它只是创建副本而不是使用已经创建的,所以我重写了模型和其他代码:

型号

#ifndef QCOMBOBOXMODEL_H
#define QCOMBOBOXMODEL_H

#include <QModelIndex>


class QComboBoxModel : public QAbstractListModel
{
public:
    QComboBoxModel(QObject *parent=nullptr);
    int rowCount(const QModelIndex &) const;
    QVariant data(const QModelIndex &index, int role) const;
    void populate(QList<QPair<int,QString>> *newValues);
    void append(int index, QString value);

private:
    QList<QPair<int,QString>> *values;
};

#endif // QCOMBOBOXMODEL_H

#include "qcomboboxmodel.h"

#include <QModelIndex>
#include <QDebug>

QComboBoxModel::QComboBoxModel(QObject *parent)
    :QAbstractListModel(parent)
{
    values = new QList<QPair<int,QString>>();
}

int QComboBoxModel::rowCount(const QModelIndex &) const
{
    return values->count();
}


QVariant QComboBoxModel::data( const QModelIndex &index, int role ) const
{        

    QVariant value;

        switch ( role )
        {
            case Qt::DisplayRole: //string
            {
                value = this->values->value(index.row()).second;
            }
            break;

            case Qt::UserRole: //data
            {
            value = this->values->value(index.row()).first;
            }
            break;

            default:
                break;
        }

    return value;
}

void QComboBoxModel::populate(QList<QPair<int,QString>> *newValues)
{
    int oldIdx = this->values->count();
    int newIdx = newValues->count();
    this->beginInsertRows(QModelIndex(), oldIdx, newIdx);
        this->values = newValues;
    endInsertRows();
}

void QComboBoxModel::append(int index, QString value)
{

    int newRow = this->values->count();

    this->beginInsertRows(QModelIndex(), newRow, newRow);

        values->append(QPair<int,QString>(index,value));

    endInsertRows();
}

主窗体

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include "qcomboboxmodel.h"

#include <QMainWindow>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void on_comboBox_currentIndexChanged(int index);

    void on_comboBox_currentIndexChanged(const QString &arg1);

    void on_pushButton_clicked();

private:
    Ui::MainWindow *ui;
    int newidx;
    QList<QPair<int,QString>> *values;
    QComboBoxModel *model;
};
#endif // MAINWINDOW_H

#include "mainwindow.h"
#include "qcomboboxmodel.h"
#include "ui_mainwindow.h"

#include <QDebug>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    values = new QList<QPair<int,QString>>();

    values->append(QPair<int,QString>(-1,"Select item"));
    values->append(QPair<int,QString>(10,"item1(0)"));
    values->append(QPair<int,QString>(11,"item1(1)"));
    values->append(QPair<int,QString>(21,"item1(2)"));
    values->append(QPair<int,QString>(32,"item1(3)"));
    values->append(QPair<int,QString>(44,"item1(4)"));

    newidx = 50;


    model = new QComboBoxModel();
    model->populate(values);
    this->ui->comboBox->setModel(model);
}

MainWindow::~MainWindow()
{
    delete ui;
}


void MainWindow::on_comboBox_currentIndexChanged(int index)
{
    qDebug() << ui->comboBox->itemData(index).value<int>();
}

void MainWindow::on_comboBox_currentIndexChanged(const QString &arg1)
{
    qDebug() << arg1;
}

void MainWindow::on_pushButton_clicked()
{
    qDebug() << "Clicked!";

    newidx++;
    QString strIdx = QString().number(newidx);

    values->append(QPair<int,QString>(newidx,"new item " + strIdx));
    model->populate(values);

    qDebug() << values->toStdList();
}

现在一切看起来都很好并且按预期工作!