Qt为QTableView使用自定义QItemDelegate

时间:2013-05-21 00:27:16

标签: c++ qt qtableview qcombobox qitemdelegate

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

enter image description here

我最大的问题是我不知道何时会使用QItemDelegate

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

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

  • 我应该何时怀疑QTableView使用我的代表。我想指定每个单元格使用哪些代理。这是可能的还是QTableView只使用一个代表?

  • 如果QComboBox显示QTableView后,我如何指定填充QItemDelegate的项目?

我在这里实施了QComboBox

  • 我尝试添加假设使用#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 的单元格的部分位于mainwindow.cpp中的注释“Enabled”下面。

qcomboboxitemdelegate.h

#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);
}

qcomboboxitemdelegate.cpp

QStandardItemModel

mainwindow.cpp:这是我初始化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(); }

的地方
QStandardItemModel

mainwindow.cpp:这是我更新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); }

的地方
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);
    }
}

修改1

qcomboboxdelegate.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);
}

mainwindow.cpp

{{1}}

3 个答案:

答案 0 :(得分:11)

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

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

如果你做的一切正确,如果你试图编辑它的值,组合框将出现在最后一列。

答案 1 :(得分:2)

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

答案 2 :(得分:0)

更简单;我发现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从未指定它是表小部件还是视图,但我认为两者都应同样有效。

对于您而言,您可以执行ui->tableWidget->setItemDelegateForColumn(2, dgtComboDelegate);,而不必创建自己的模型。只需在为其创建的项目上使用setData()即可初始化其值。