Использование делегатов для редактирования нескольких элементов данных одновременно - PullRequest
3 голосов
/ 15 февраля 2012

В моем приложении QSqlTableModel заполнено таблицей из соединения MySQL. Чтобы показать его содержимое, я использую QTableView; и чтобы редактировать и отображать его, я вложил в подкласс QStyledItemDelegate.

Мне нужно иметь возможность редактировать всю строку модели. Для этого я использую метод QModelIndex::sibling, чтобы получить / установить все значения в этой строке независимо от того, какая пара (строка / столбец) «активировала» делегат.

С этим я могу построить подкласс QDialog (мой редактор делегатов) и заполнить его текущими значениями выбранной строки. А затем разрешите пользователю редактировать содержимое и после принятия изменений или отмены их, в зависимости от того, нажал ли пользователь «сохранить» или «отменить».

Проблема в том, что я использую QAbstractItemModel::setData для сохранения изменений обратно в модель. Но при определенных условиях (пока неизвестных) этот метод вызывает QAbstractItemDelegate::setEditorData, который перезаписывает новый контент, который находится в подклассе QDialog для старого контента, присутствующего в настоящее время в модели.

Когда это происходит, любой следующий вызов QAbstractItemModel::setData запишет содержимое, содержащееся в модели, само по себе, а не новое значение, выбранное пользователем, поскольку предыдущий вызов QAbstractItemDelegate::setEditorData привел к потере подкласса QDialog вся информация, выбранная пользователем, из столбца, соответствующего QAbstractItemModel::setData, который вызвал проблему.

Кто-нибудь знает, как предотвратить возникновение этой проблемы?

Некий код:

QWidget *MedicationDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem&       /*option*/, const QModelIndex& /*index*/) const
{
    EditMedicationDialog *editor = new EditMedicationDialog(parent);
    editor->setAttribute(Qt::WA_DeleteOnClose, true);
    editor->setModal(true);

    connect(editor, SIGNAL(accepted()), this, SLOT(editorAccepted()));
    connect(editor, SIGNAL(rejected()), this, SLOT(editorRejected()));

    return editor;
}

void MedicationDelegate::setEditorData(QWidget *uncastedEditor, const QModelIndex& index) const
{
    int currentRow = index.row();

    QModelIndex drugClassIndex = index.sibling(currentRow, MedicationModel::DrugClass);
    QModelIndex drugIndex = index.sibling(currentRow, MedicationModel::Drug);
    QModelIndex dosageIndex = index.sibling(currentRow, MedicationModel::Dosage);
    QModelIndex amountIndex = index.sibling(currentRow, MedicationModel::Amount);
    QModelIndex scheduleIndex = index.sibling(currentRow, MedicationModel::Schedule);
    QModelIndex frequencyIndex = index.sibling(currentRow, MedicationModel::Frequency);

    QString drugClass = index.model()->data(drugClassIndex, Qt::DisplayRole).toString();
    QString drug = index.model()->data(drugIndex, Qt::DisplayRole).toString();
    QString dosage = index.model()->data(dosageIndex, Qt::DisplayRole).toString();
    QString amount = index.model()->data(amountIndex, Qt::DisplayRole).toString();
    QString schedule = index.model()->data(scheduleIndex, Qt::DisplayRole).toString();
    QString frequency = index.model()->data(frequencyIndex, Qt::DisplayRole).toString();

    EditMedicationDialog *editor = qobject_cast<EditMedicationDialog*>(uncastedEditor);

    // these methods sets the current row values in the editor
    editor->setDrugClass(drugClass);
    editor->setDrug(drug);
    editor->setDosage(dosage);
    editor->setAmount(amount);
    editor->setSchedule(schedule);
    editor->setFrequency(frequency);
}

void MedicationDelegate::setModelData(QWidget *uncastedEditor, QAbstractItemModel *model, const QModelIndex& index) const
{
    int currentRow = index.row();

    QModelIndex drugClassIndex = index.sibling(currentRow, MedicationModel::DrugClass);
    QModelIndex drugIndex = index.sibling(currentRow, MedicationModel::Drug);
    QModelIndex dosageIndex = index.sibling(currentRow, MedicationModel::Dosage);
    QModelIndex amountIndex = index.sibling(currentRow, MedicationModel::Amount);
    QModelIndex scheduleIndex = index.sibling(currentRow, MedicationModel::Schedule);
    QModelIndex frequencyIndex = index.sibling(currentRow, MedicationModel::Frequency);

    EditMedicationDialog *editor = qobject_cast<EditMedicationDialog*>(uncastedEditor);

    model->setData(drugClassIndex, editor->drugClass());
    model->setData(drugIndex, editor->drug()); // HERE
    model->setData(dosageIndex, editor->dosage());
    model->setData(amountIndex, editor->amount());
    model->setData(scheduleIndex, editor->schedule());
    model->setData(frequencyIndex, editor->frequency());
}

Строка с комментарием "ЗДЕСЬ" вызывает проблему (согласно отладке).

РЕДАКТИРОВАТЬ (новая информация): Я просто понимаю, что QAbstractItemModel::setData всегда вызывается сразу после того, как столбец, вызвавший «редактирование», сохраняется. Я всегда давал два клика в колонке «наркотик». Поэтому QAbstractItemDelegate::setEditorData вызывается после этого издания.

Спасибо.

1 Ответ

0 голосов
/ 19 февраля 2012

Вы можете использовать логическое значение для предотвращения рекурсивного выполнения тела функции.

Более простое решение будет

  • , чтобы сделать модель доступной только для чтения, установив триггеры редактирования на QAbstractItemView::NoEditTriggers,
  • для использования, например, сигнала clicked представления, чтобы открыть / показать QDialog вместо делегата,
  • и связать элементы управления в диалоге с полями модели с QDataWidgetMapper.

Затем тот же QDialog можно было бы использовать повторно, и вы бы заполнили элементы управления QDataWidgetMapper::setCurrentIndex, прежде чем показывать его с exec() и либо QDataWidgetMapper::submit(), либо revert() после того, как пользователь подтвердит или отменит изменения.

Поскольку QDataWidgetMapper и QTableView будут использовать одну и ту же модель, представление таблицы будет автоматически обновлено.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...