【问题标题】:Qt Using Custom QItemDelegate for QTableViewQt 为 QTableView 使用自定义 QItemDelegate
【发布时间】:2013-05-15 15:31:37
【问题描述】:

我按照 Qt 提供的 Spin Box Delegate 教程来尝试实现我自己的 QItemDelegate。它将用于指定 QComboBox 来表示 QTableView 单元格中的数据,但它不起作用。

我最大的问题是我不知道我的QItemDelegate 什么时候会被使用。

  • 当使用itemModel->setData()itemModel->setItem() 时。我会怀疑setItem(),因为我重新实现了QItemDelegate(强调“项目”),但本教程使用setData(),它工作正常。

  • 我知道如果指定的QItemDelegate 不起作用,它会使用默认的,但是我现在指定的那个不起作用怎么办?

  • 我应该什么时候怀疑QTableView 使用我的委托。我想指定每个单元格使用哪些代表。这是可能的还是QTableView 始终只使用一个代表?

  • 一旦QTableView 显示QComboBox,我将如何指定要填充的项目?

我在这里实现了QItemDelegate

  • 我尝试添加假定使用 QComboBox 的单元格的部分位于本文下方 mainwindow.cpp 中的“已启用”注释下。

qcomboboxitemdelegate.h

#ifndef QCOMBOBOXITEMDELEGATE_H
#define QCOMBOBOXITEMDELEGATE_H

#include <QItemDelegate>
#include <QComboBox>

class QComboBoxItemDelegate : public QItemDelegate
{
    Q_OBJECT

public: 

    explicit QComboBoxItemDelegate(QObject *parent = 0);

    QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index);
    void setEditorData(QWidget *editor, const QModelIndex &index);
    void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index);
    void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option,     const QModelIndex &index);

signals:

private:

};

#endif // QCOMBOBOXITEMDELEGATE_H

qcomboboxitemdelegate.cpp

#include "qcomboboxitemdelegate.h"
#include <QDebug>

QComboBoxItemDelegate::QComboBoxItemDelegate(QObject *parent)
: QItemDelegate(parent)
{

}

QWidget* QComboBoxItemDelegate::createEditor(QWidget *parent, const   QStyleOptionViewItem &option, const QModelIndex &index) {
    // create widget for use
    QComboBox* comboBox = new QComboBox(parent);
    return comboBox;
}

void QComboBoxItemDelegate::setEditorData(QWidget *editor, const QModelIndex &index) {
    // update model widget
    QString value = index.model()->data(index, Qt::EditRole).toString();
    qDebug() << "Value:" << value;
    QComboBox* comboBox = static_cast<QComboBox*>(editor);
    comboBox->setCurrentIndex(comboBox->findText(value));
}

void QComboBoxItemDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,   const QModelIndex &index) {
    // store edited model data to model
    QComboBox* comboBox = static_cast<QComboBox*>(editor);
    QString value = comboBox->currentText();
    model->setData(index, value, Qt::EditRole);
}

void QComboBoxItemDelegate::updateEditorGeometry(QWidget *editor, const     QStyleOptionViewItem &option, const QModelIndex &index) {
    editor->setGeometry(option.rect);
}

mainwindow.cpp : 这是我初始化QStandardItemModel的地方

void MainWindow::init() {
    itemModel = new QStandardItemModel(this);
}

void MainWindow::setupUi() {
    this->setWindowTitle("QAlarmClock");        
    QStringList labelList;
    labelList << "Alarm Name" << "Time" << "Enabled";
    itemModel->setHorizontalHeaderLabels(labelList);    
    ui->tableView->setModel(itemModel);
    ui->tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
    ui->tableView->setItemDelegate(comboBoxItemDelegate);
}

void MainWindow::on_actionNew_triggered() {
    alarmDialog = new AlarmDialog(this);
    connect(alarmDialog, SIGNAL(on_close()), this, SLOT(on_alarmDialog_close()));
    alarmDialog->exec();
}

mainwindow.cpp : 这是我更新QStandardItemModel的地方

void MainWindow::on_alarmDialog_close() {
    QString alarmName = alarmDialog->getAlarmName();
    QDateTime alarmDateTime = alarmDialog->getDateTime();

    itemModel->insertRow(itemModel->rowCount());
    int rowCount = itemModel->rowCount();

    // Alarm Name
    QStandardItem* alarmItem = new QStandardItem(QIcon("res/alarmclock.ico"),  alarmName);
    itemModel->setItem(rowCount - 1 , 0, alarmItem);

    // Date Time
    QStandardItem* dateTimeItem = new QStandardItem();
    dateTimeItem->setText(alarmDateTime.toString());
    dateTimeItem->setEditable(false);
    itemModel->setItem(rowCount - 1, 1, dateTimeItem);

    // Enabled
    QStandardItem* enabledItem = new QStandardItem();
    QList<QStandardItem*> optionList;
    optionList << new QStandardItem("Enabled") << new QStandardItem("Disabled");
    enabledItem->appendRows(optionList);
    itemModel->setItem(rowCount - 1, 2, enabledItem);
}

编辑 1

qcomboboxdelegate.cpp

QWidget* QComboBoxItemDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) {
    // create widget for use
    qDebug() << "Column: " << index.column();
    if (index.column() == 2) {
        QComboBox* comboBox = new QComboBox(parent);
        QStringList values;
        values << "Enabled" << "Disabled";
        comboBox->addItems(values);
        return comboBox;
    } else {
        return QItemDelegate::createEditor(parent, option, index);
    }
}

主窗口.cpp

void MainWindow::on_alarmDialog_close() {
    QList<QStandardItem*> row;

    QString alarmName = alarmDialog->getAlarmName();
    QDateTime alarmDateTime = alarmDialog->getDateTime();
    QString status = "Enabled";

    // Alarm Name
    QStandardItem* alarmItem = new QStandardItem(QIcon("res/alarmclock.ico"), alarmName);
    row << alarmItem;

    // Date Time
    QStandardItem* dateTimeItem = new QStandardItem();
    dateTimeItem->setText(alarmDateTime.toString());
    dateTimeItem->setEditable(false);
    row << dateTimeItem;

    // Enabled
    QStandardItem* statusItem = new QStandardItem(status);
    row << statusItem;

    itemModel->appendRow(row);
}

【问题讨论】:

    标签: c++ qt qtableview qcombobox qitemdelegate


    【解决方案1】:

    更简单;我发现 QTableView::setItemDelegateForColumn() 非常适合列。例如,在您的 MainWindow 中,您可以创建一个成员:

    QComboBoxItemDelegate dgtComboDelegate;
    

    然后,在您的 ctor 或 init() 中,您可以拥有

    ui->tableView->setItemDelegateForColumn(2, dgtComboDelegate);
    

    如果您希望单个单元格发生这种情况,那么您需要在 index.column() 和 index.row() 上进行测试。

    您知道,您也不必创建 QTableView 来执行此操作。例如,查看 ?:

    Qt - Centering a checkbox in a QTable

    OP 没有给出表格小部件或视图的声明;但它确实有 QTableView 标签。它应该同样适用于任何一个。

    在前一种情况下,您可以使用ui-&gt;tableWidget-&gt;setItemDelegateForColumn(2, dgtComboDelegate);,而不必制作自己的模型。只需对您创建的项目(或者甚至稍后,就此而言)使用 setData() 来初始化它们的值。

    【讨论】:

      【解决方案2】:

      首先,您应该对模型列进行描述:

      enum Columns
      {
          COL_NAME,
          COL_TIME,
          COL_STATUS
      }
      

      您的代表应该只为最后一列工作。

      以下是如何填充模型的示例:

      for (int i = 0; i < 5; ++i)
      {
          QStandardItem *itemName = new QStandardItem(QString("name %1").arg(i));
          QStandardItem *itemTime = new QStandardItem(QString("time %1").arg(i));
      
          QString status;
          if (i % 2 == 0)
          {
              status = "Enabled";
          }
          else
          {
              status = "Disabled";
          }
      
          QStandardItem *itemStatus = new QStandardItem(status);
      
          QList<QStandardItem*> row;
          row << itemName << itemTime << itemStatus;
      
          model->appendRow(row);
      }
      

      正如我所说,您的代表应该只为最后一栏工作。所以你重新实现的所有方法都应该有这样的列检查:

      QWidget* QComboBoxItemDelegate::createEditor(QWidget *parent, 
                                  const QStyleOptionViewItem &option, 
                                  const QModelIndex &index) 
      {
          if (index.column() == COL_STATUS)
          {
              QStringList values;
              values << "Enabled" << "Disabled";
      
              QComboBox* comboBox = new QComboBox(parent);
              comboBox->addItems(values);
              return comboBox;
          }
          else
          {
              return QItemDelegate::createEditor(parent, option, index);
          }
      }
      

      您应该将此检查添加到其他方法中:如果当前列不是状态列,则应使用基类 (QItemDelegate) 实现。

      然后您将委托设置为您的视图:

      ui->tableView->setItemDelegate(new ComboBoxDelegate);
      

      如果你做的一切正确,如果你尝试编辑它的值,最后一列中会出现一个组合框。

      【讨论】:

      • 我应该什么时候调用 ui->tableView->setItemDelegate(new ComboBoxDelegate);?我在我的 SetupUI() 中调用它,在向 tableView 添加任何内容之前调用它,并且在进行更改之后它仍然不起作用。我还测试了在 appendRow() 之后调用它,但它仍然不起作用。我在 QComboxItemDelegate 中放置了一些调试语句,以查看它走了多远,但 createEditor() 没有被调用
      • 在此语句之后:“ui->tableView->setItemDelegate(new ComboBoxDelegate);”哪个对象将负责取消分配(新 ComboBoxDelegate)?
      • 还有什么时候应该调用这个类的destructor(),我在里面放了一个debug语句,没有输出
      【解决方案3】:

      所以我发现我没有覆盖正确的函数原型..!我忘了他们 在原型中有 const 意味着我没有覆盖任何函数,所以它使用的是默认函数。以下是必须重新实现的正确虚函数:http://qt-project.org/doc/qt-5.0/qtwidgets/qitemdelegate.html

      【讨论】:

      • 如果您通过 hank 解决了问题,您应该给予他信任,而不是给自己检查正确的答案,编辑和/或评论他/她的答案。
      • 为了防止将来出现此类问题,我强烈建议使用 C++11 的 override 关键字。 en.cppreference.com/w/cpp/language/override
      • 考虑到我已经编辑了 8 个单元格,我想在每个单元格都被编辑后释放 qcombobox,那么在哪里删除呢?
      猜你喜欢
      • 2017-11-07
      • 1970-01-01
      • 2017-07-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多