J'ai suivi le didacticiel de Spin Box Delegate, fourni par Qt, pour essayer de mettre en œuvre ma propre QItemDelegate
. Il serait utilisé pour spécifier une QComboBox
afin de représenter des données dans une cellule QTableView
mais cela ne fonctionne pas.
Mon plus gros problème est que je ne sais pas quand ma QItemDelegate
sera utilisée.
quand itemModel->setData()
est utilisé ou quand itemModel->setItem()
. Je suspecterais setItem()
parce que j’ai réimplémenté un QItemDelegate
(en mettant l’accent sur "l'élément") mais le tutoriel utilise setData()
et tout fonctionne correctement.
Je sais que si la QItemDelegate
spécifiée ne fonctionne pas, elle utilise celle par défaut, mais comment puis-je maintenant que celle que j'ai spécifiée ne fonctionne pas?
quand devrais-je soupçonner que QTableView
utilise mon délégué? Je voudrais spécifier les délégués à utiliser pour chaque cellule. Est-ce possible ou la QTableView
emploie-t-elle un seul délégué?
Comment pourrais-je spécifier les éléments pour renseigner la QComboBox
une fois affichée par la QTableView
?
J'ai implémenté QItemDelegate
ici:
QComboBox
se trouve sous le commentaire "Activé" dans le fichier mainwindow.cpp plus loin dans cet article.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: c’est là que j’initialise la 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: c'est ici que je mets à jour 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);
}
Éditer 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);
}
Tout d'abord, vous devriez avoir une description de vos colonnes de modèle:
enum Columns
{
COL_NAME,
COL_TIME,
COL_STATUS
}
Votre délégué ne devrait travailler que pour la dernière colonne.
Voici un exemple de la façon dont vous pouvez remplir votre modèle:
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);
}
Comme je l'ai dit, votre délégué ne devrait travailler que pour la dernière colonne. Ainsi, toutes les méthodes que vous avez réimplémentées devraient avoir une vérification de colonne comme celle-ci:
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);
}
}
Vous devez ajouter cette vérification aux autres méthodes: si la colonne en cours n'est pas la colonne d'état, l'implémentation de la classe de base (QItemDelegate
) doit être utilisée.
Ensuite, vous définissez votre délégué à votre vue:
ui->tableView->setItemDelegate(new ComboBoxDelegate);
Si vous faites tout bien, une liste déroulante apparaîtra dans la dernière colonne si vous essayez d’éditer ses valeurs.
J'ai donc compris que je n'avais pas remplacé les prototypes de fonctions corrects ..! J'ai oublié qu'ils contenaient dans le prototype, ce qui signifie que je ne remplaçais aucune fonction et utilisait donc les fonctions par défaut. Voici les fonctions virtuelles correctes qui doivent être ré-implémentées: http://qt-project.org/doc/qt-5.0/qtwidgets/qitemdelegate.html
Encore plus simplement; J'ai trouvé que QTableView :: setItemDelegateForColumn () fonctionnait admirablement pour une colonne. Par exemple, dans votre MainWindow, vous pouvez faire un membre:
QComboBoxItemDelegate dgtComboDelegate;
Ensuite, dans votre ctor ou init (), vous pourriez avoir
ui->tableView->setItemDelegateForColumn(2, dgtComboDelegate);
Si vous voulez que cela se produise pour une seule cellule, vous devez alors tester sur index.column () et index.row ().
Vous savez, vous n'avez pas non plus besoin de créer un QTableView. Par exemple, voir le?:
Qt - Centrer une case dans une QTable
Bien que l'OP ne spécifie jamais s'il s'agit d'un widget ou d'une vue de table, je pense que cela devrait fonctionner aussi bien pour l'un que pour l'autre.
Dans votre cas, vous pouvez utiliser ui->tableWidget->setItemDelegateForColumn(2, dgtComboDelegate);
et ne jamais avoir à créer votre propre modèle. Il suffit d'utiliser setData () sur les éléments que vous créez pour qu'il initialise leurs valeurs.