web-dev-qa-db-fra.com

Qt à l'aide de QItemDelegate personnalisé pour QTableView

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.

 enter image description here

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:

  • la partie où j'essaie d'ajouter la cellule supposée utiliser la variable 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);
}
11
arnm

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.

10
hank

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

2
arnm

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.

0
CodeLurker