【问题标题】:How to force a model to update QComboBox when data changed?数据更改时如何强制模型更新 QComboBox?
【发布时间】:2020-10-26 02:03:15
【问题描述】:

我为 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);

这是一个正确的方法吗?或者还有其他方法可以在数据更新时强制模型更新组合框?

【问题讨论】:

    标签: c++ qt model qt5 qcombobox


    【解决方案1】:

    根据文档中的“模型子类化参考”,您必须做更多的事情来制作可编辑的模型。您是否有理由不使用像 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();
    

    【讨论】:

      【解决方案2】:

      我找到了解决办法!

      首先我向模型添加新方法

      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)"))
      

      更新 2:

      我也更新了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();
      }
      

      现在一切看起来都很好,可以按预期工作!

      【讨论】:

        【解决方案3】:

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

        【讨论】:

        • 不,它不起作用 QComboBoxModel *m = (QComboBoxModel *)this->ui->comboBox->model(); this->ui->comboBox->setModel(m);
        • 具体的错误/问题是什么?你为什么要投射而不保留基类? (顺便说一句:C 风格的演员表不像 CPP:见 stackoverflow.com/questions/43994584/what-is-qobject-cast)'auto' 是你的朋友。
        • 我刚刚试了一下。 QComboBox 来自一个 ui 文件(第一行..)。然后更改了第一项的值。 ` auto* cb = ui->myCB; cb->insertItem(0, "foo"); cb->insertItem(1, "bar");自动*模型= cb->模型();模型->setData(model->index(0,0), "not foo"); cb->setModel(模型);`
        • 没有错误点是最佳实践,我需要更新“值”,然后只需使用模型更新更新组合框。我尝试了不同的方法,但没有奏效。您建议使用 setData 但我不想使用那种复杂的方法,我只需向数组添加新元素,然后更新组合框。
        • 好的,像这样 QComboBoxModel *m = dynamic_cast(ui->comboBox->model()); m->填充(值); this->ui->comboBox->setModel(m);它似乎工作正常,但是有一个错误,当我按下按钮时它会将项目添加到 cb,但是当我打开组合框以检查项目并尝试添加更多之后,它没有添加新项目:(
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-05-13
        • 1970-01-01
        • 1970-01-01
        • 2020-04-14
        • 2012-11-15
        相关资源
        最近更新 更多