Qt Использование собственного QItemDelegate для QTableView

Я следовал учебнику Spin Box Delegate, который предоставляет Qt, чтобы попытаться реализовать свой собственный QItemDelegate, Это будет использоваться для указания QComboBox представлять данные в QTableView клетка, но она не работает.

введите описание изображения здесь

Моя самая большая проблема в том, что я не знаю, когда мой QItemDelegate будет использоваться.

  • когда itemModel->setData() используется или когда itemModel->setItem(), Я бы заподозрил setItem() потому что я переопределил QItemDelegate (акцент на «Предмет»), но учебник использует setData() и работает нормально.

  • Я знаю, что если указано QItemDelegate не работает, он использует по умолчанию, но как мне теперь, чтобы тот, который я указал, не работал?

  • когда я должен подозревать QTableView использовать мой делегат. Я хотел бы указать, какие делегаты использовать для каждой ячейки. Это возможно или делает QTableView использовать только один делегат?

  • Как бы я указать элементы для заполнения QComboBox как только он отображается QTableView?

Я реализовал 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);
}
}

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

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

Если вы все сделаете правильно, в последнем столбце появится поле со списком, если вы попытаетесь изменить его значения.

10

Другие решения

Поэтому я понял, что я не переопределил правильные прототипы функций ..! Я забыл что они
в прототипе имелось const, означающее, что я не переопределял никакие функции, поэтому он использовал стандартные функции. Вот правильные виртуальные функции, которые должны быть повторно реализованы: http://qt-project.org/doc/qt-5.0/qtwidgets/qitemdelegate.html

2

Еще проще; Я обнаружил, что QTableView :: setItemDelegateForColumn () работает превосходно для столбца. Например, в вашем MainWindow вы можете сделать член:

QComboBoxItemDelegate dgtComboDelegate;

Затем в вашем ctor или init () вы могли бы иметь

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

Если вы хотите, чтобы это произошло для одной ячейки, тогда вам нужно протестировать функции index.column () и index.row ().

Вы знаете, вам не нужно создавать QTableView, чтобы сделать это тоже. Например, увидеть?

Qt — Центрирование флажка в QTable

Хотя ОП никогда не указывает, является ли это виджетом или представлением таблицы, я думаю, что он должен одинаково хорошо работать для обоих.

В вашем случае вы можете сделать ui->tableWidget->setItemDelegateForColumn(2, dgtComboDelegate); и никогда не придется делать свою собственную модель. Просто используйте setData () для элементов, которые вы создаете для инициализации их значений.

0
По вопросам рекламы [email protected]