Model View Tutorial Part2 Delegate und View/de

From Qt Wiki
Jump to: navigation, search
This article may require cleanup to meet the Qt Wiki's quality standards. Reason: Auto-imported from ExpressionEngine.
Please improve this article if you can. Remove the {{cleanup}} tag and add this page to Updated pages list after it's clean.

←Teil 2: editierbares Datenmodell
↑Übersicht Model/View Tutorial:CD Verwaltung↑
Teil 3: Zeilen / Spalten hinzufügen / entfernen→

Implementierung eines einfachen Delegates

Zum Editieren eines Modells genügt es im Einfachsten Fall, wenn die Methode flags() das Flag Qt::ItemIsEditable liefert und bei data(…) und setData(…) die Rolle Qt::EditRole implementiert ist. Um ein Datum oder einen Integer nicht in einem Textfeld sondern einem Standardeditor für den jeweiligen Datentypen zu editieren, genügt es bei data() für die Qt::EditRole das Datum nativ in den QVariant zu schreiben, und nicht in Text umgewandelt, was bei einem Datum für die Qt::DisplayRole durchaus Sinn machen kann (z.B. wenn eine spezielle Formatierung gewünscht wird).

In unserem Beispiel leiten wir von QItemDelegate ab, der dieses beschriebene Verhalten bereits implementiert. Beim Erzeugen eines eigenen Delegates muss darauf geachtet werden, dass immer, wenn es keine eigene Implementierung gibt, die Basisklasse aufgerufen wird.

Sobald aber aus dem Datentyp der Editor nicht eineindeutig bestimmt werden kann, Grenzwerte oder Validierungen (=Gültigkeitsprüfungen) benötigt werden, muss man selbst Hand anlegen: man muss einen so genannten Delegate (von QAbstractItemDelegate [doc.qt.nokia.com] abgeleitet) erstellen.

Mit einem Delegate kann man folgende Dinge machen:

  • Spezielles Editieren von Elementen in einer View
  • Spezielle Darstellung von Elementen (z.B. ein Fortschrittsbalken in einer Tabelle)
    Hier ein Beispiel aus der Qt-Dokumentation:
    aus der Qt docu

In unserem Beispiel wollen wir zum Bearbeiten der Genres eine Combo Box nutzen, mit der wir ein existierendes Genre auswählen oder ein neues eingeben können. Dazu überschreiben wir die folgenden Methoden:

createEditor

Mittels createEditor wird das Widget erzeugt, das zum Editieren benutzt werden soll. Hier können Standardwerte (wie autoComplete etc.) gesetzt werden, die üblicherweise zum Erzeugen des Widgets gehören. Bei einem Delegate muss immer der Index geprüft werden. Es kann auch ein Delegate für mehrere Views bzw. Modelle genutzt werden, daher sollte bei Zugriffen auf das Modell immer index.model oder bei setModeldata der Parameter model benutzt werden.

  1. QWidget* CdEditDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index ) const
  2. {
  3.     // the genre column has index 2
  4.     if(2 == index.column())
  5.     {
  6.         QComboBox* pEditor = new QComboBox(parent);
  7.         pEditor->setEditable(true);
  8.         pEditor->setAutoCompletion(true);
  9.         return pEditor;
  10.     }
  11.     return QItemDelegate::createEditor(parent, option, index);
  12. }

setEditorData

Die Methode setEditorData wird nach createEditor aufgerufen. Sie wird benutzt, um das Editor-Widget mit Daten zu füllen. In unserem Beispiel fügen wir die Genres der ComboBox hinzu und setzen den aktuell selektierten Wert.

  1. void CdEditDelegate::setEditorData(QWidget* editor, const QModelIndex& index ) const
  2. {
  3.     // the genre column has index 2
  4.     if(2 == index.column())
  5.     {
  6.         QComboBox* pEditor = qobject_cast<QComboBox*>(editor);
  7.         if(0 != pEditor)
  8.         {
  9.             pEditor->addItems(m_pData->genres());
  10.             pEditor->setCurrentIndex(pEditor->findText(index.data().toString()));
  11.         }
  12.     }
  13.     QItemDelegate::setEditorData(editor, index);
  14. }

setModelData

Die Methode setModelData wird aufgerufen, wenn das Editieren einer Zelle beendet wird. Das kann sein, weil mit der Maus woanders hingeklickt oder die Tabulator- oder Eingabetaste gedrückt wurde. Hier kann im Zweifelsfall nochmal der Wert validiert und dann ins Modell geschrieben werden. Das Beenden des Editierens (z.B. im Fehlerfall) ist hier nicht mehr möglich, da der Fokus evtl. schon woanders ist.

In unserem Beispiel fragen wir den Wert aus der ComboBox ab und schreiben ihn mittels setData ins Modell.

  1. void CdEditDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index ) const
  2. {
  3.     // the genre column has index 2
  4.     if(2 == index.column())
  5.     {
  6.         QComboBox* pEditor = qobject_cast<QComboBox*>(editor);
  7.         if(0 != pEditor)
  8.         {
  9.             model->setData(index, pEditor->currentText());
  10.             return;
  11.         }
  12.     }
  13.     QItemDelegate::setModelData(editor, model, index);
  14. }

updateEditorGeometry

Die Methode updateEditorGeometry wird aufgerufen, um den Editor in der Tabelle korrekt zu platzieren. Die Basisklasse QItemdelegate macht bereits alles, was wir benötigen, deswegen rufen wir einfach die Basisimplementierung auf.

  1. void CdEditDelegate::updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index ) const
  2. {
  3.     QItemDelegate::updateEditorGeometry(editor, option, index);
  4. }

Ändern von Editiereigenschaften der View

Um einen Delegate in einer View zu verwenden, muss folgendes gemacht werden:

  1. Erzeugen des Delegates auf dem Heap mit new
  2. setItemdelegate [doc.qt.nokia.com] in der View aufrufen

Weiterhin kann mittels setEditTriggers [doc.qt.nokia.com] eingestellt werden, durch welche Ereignisse das Editieren einer Zelle begonnen werden soll:

Konstante Beschreibung
QAbstractItemView::NoEditTriggers kein Editieren möglich.
QAbstractItemView::CurrentChanged Das Editieren wird gestartet, wenn das aktuelle Element gewechselt wird.
QAbstractItemView::DoubleClicked Das Editieren startet mit einem Doppelklick auf ein Element.
QAbstractItemView::SelectedClicked Das Editieren wird gestartet, wenn auf ein bereits selektiertes Element geklickt wird.
QAbstractItemView::EditKeyPressed Das Editieren wird gestartet, wenn die plattformspezifische Bearbeiten-Taste gedrückt wird.
QAbstractItemView::AnyKeyPressed Das Editieren wird gestartet, wenn irgend eine Taste gedrückt wird (Außer Tab oder Cursor).
QAbstractItemView::AllEditTriggers Das Editieren wird in allen oben genannten Fällen gestartet
  1. void CVirtualCdRack::init()
  2. {
  3.     ....
  4.  
  5.     m_model = new CdModel(m_data, this);
  6.     m_view = new QTableView;
  7.     m_view->setModel(m_model);
  8.     m_view->setAlternatingRowColors(true);
  9.     m_view->setEditTriggers(QAbstractItemView::DoubleClicked |
  10.                             QAbstractItemView::SelectedClicked |
  11.                             QAbstractItemView::EditKeyPressed |
  12.                             QAbstractItemView::AnyKeyPressed);
  13.     CdEditDelegate* pDelegate = new CdEditDelegate(&m_data, m_view);
  14.     m_view->setItemDelegate(pDelegate);
  15.     setCentralWidget(m_view);
  16.  
  17.     ....
  18. }