Model View Tutorial Part2/de: Difference between revisions

From Qt Wiki
Jump to navigation Jump to search
No edit summary
 
No edit summary
Line 1: Line 1:
<div class="factbox right">


===Table of Content===
* [[#6cf652940458d1314e876f9344973bb6|Ein Modell, dessen Werte editiert werden können]]
** [[#4e5868d676cb634aa75b125a0f741abf|flags]]
** [[#8feaa50ca223fd78d6e50b2649d94ddc|setData]]
</div>
[http://qt.io/groups/qt_german/wiki/Model-View-Tutorial-Teil1 ←Teil 1: Table Modell]<br />[http://qt.io/groups/qt_german/wiki/Model_View_Tutorial ↑Übersicht Model/View Tutorial:CD Verwaltung↑]<br />[http://qt.io/groups/qt_german/wiki/Model-View-Tutorial-Teil2-Delegate-und-View Teil 2: Delegate und View→]
=Ein Modell, dessen Werte editiert werden können=
Damit Werte in einem Modell editiert werden können, muss die Methode '''flags(…)''' überschrieben werden und für alle editierbaren Zellen auch das flag '''Qt::ItemIsEditable''' zurückliefern. Außerdem muss die Methode '''setData''' überschrieben werden, da diese von der View aufgerufen wird, um Werte in das Modell zu schreiben.
Wenn die Methode '''setData()''' überschrieben wird, muss nach dem Ändern der Werte das Signal '''dataChanged()''' explizit ausgelöst werden. Bleibt das Signal aus, dann fehlt den mit dem Modell verbundenen Views der Impuls, ihren Zustand aktualisieren.
Es sind also diese beiden [http://qt.io/groups/qt_german/wiki/virtuellen-Funktionen virtuellen Funktionen] zu überschreiben:
* Qt::ItemFlags flags(const QModelIndex&amp; index ) const
* bool setData(const QModelIndex&amp; index, const QVariant&amp; value, int role)
Im folgenden wird deren Implementierungen beschrieben
==flags==
Die Methode [http://doc.qt.nokia.com/latest/qabstractitemmodel.html#flags flags()] ''[doc.qt.nokia.com]'' wird benutzt, wenn man Eigenschaften eines Modell-Elements ändern möchte. Die am häufigsten benötigten sind:
{| class="infotable line"
| '''Wert'''
| '''Beschreibung'''
|-
| '''Qt::ItemIsSelectable'''
| Das Element kann selektiert werden (Standard).
|-
| '''Qt::ItemIsEditable'''
| Das Element kann editiert werden.
|-
| '''Qt::ItemIsUserCheckable'''
| Das Element kann (üblicherweise mittels einer Checkbox) angekreuzt werden.
|-
| '''Qt::ItemIsEnabled'''
| Der Benutzer kann mit dem Element interagieren (Standard).
|}
Wird für ein Element ''Qt::ItemIsUserCheckable'' zurückgegeben, wird bei setData auch die Rolle Qt::CheckStateRole übergeben.
In unserem einfachen Beispiel kann jedes Element editiert werden:
<div class="cpp-qt geshi">
# <div class="de1">[http://doc.qt.io/Qt.html <span class="kw5">Qt</span>]<span class="sy0">::</span><span class="me2">ItemFlags</span> CdModel<span class="sy0">::</span><span class="me2">flags</span><span class="br0">(</span><span class="kw4">const</span> [http://doc.qt.io/QModelIndex.html <span class="kw5">QModelIndex</span>]<span class="sy0">&amp;</span> index <span class="br0">)</span> <span class="kw4">const</span></div>
# <div class="de1"><span class="br0">{</span></div>
# <div class="de1">    <span class="kw1">if</span><span class="br0">(</span>index.<span class="me1">isValid</span><span class="br0">(</span><span class="br0">)</span><span class="br0">)</span></div>
# <div class="de1">        <span class="kw1">return</span> [http://doc.qt.io/Qt.html <span class="kw5">Qt</span>]<span class="sy0">::</span><span class="me2">ItemIsEnabled</span> <span class="sy0">|</span> [http://doc.qt.io/Qt.html <span class="kw5">Qt</span>]<span class="sy0">::</span><span class="me2">ItemIsSelectable</span> <span class="sy0">|</span> [http://doc.qt.io/Qt.html <span class="kw5">Qt</span>]<span class="sy0">::</span><span class="me2">ItemIsEditable</span><span class="sy0">;</span></div>
# <div class="de2"> </div>
# <div class="de1">    <span class="kw1">return</span> [http://doc.qt.io/QAbstractItemModel.html <span class="kw5">QAbstractItemModel</span>]<span class="sy0">::</span><span class="me2">flags</span><span class="br0">(</span>index<span class="br0">)</span><span class="sy0">;</span></div>
# <div class="de1"><span class="br0">}</span></div>
</div>
==setData==
Die Methode [http://doc.qt.nokia.com/latest/qabstractitemmodel.html#setData setData] ''[doc.qt.nokia.com]'' wird von der View (bzw. eigentlich dem Delegate, siehe später) aufgerufen, um die Werte zu setzen. Es können all die Werte gesetzt werden, die mittels data() auch gelesen werden können. Als erstes müssen die Übergabeparameter validiert (= auf ihre Gültigkeit geprüft werden) werden. Dann muss die Rolle überprüft und die Werte im Datenmodell geändert werden. Abschließend ''muss'' das Signal dataChanged ausgelöst werden. Wird das vergessen, wird die Datenänderung nicht in der View angezeigt.
Sollte ein Editiervorgang nicht klappen, ''muss'' die Methode '''false''' zurückliefern, ansonsten true.
In unserem einfachen Beispiel verwenden wir die folgende Implementierung:
<div class="cpp-qt geshi">
# <div class="de1"><span class="kw4">bool</span> CdModel<span class="sy0">::</span><span class="me2">setData</span><span class="br0">(</span><span class="kw4">const</span> [http://doc.qt.io/QModelIndex.html <span class="kw5">QModelIndex</span>]<span class="sy0">&amp;</span> index<span class="sy0">,</span> <span class="kw4">const</span> [http://doc.qt.io/QVariant.html <span class="kw5">QVariant</span>]<span class="sy0">&amp;</span> value<span class="sy0">,</span> <span class="kw4">int</span> role<span class="br0">)</span></div>
# <div class="de1"><span class="br0">{</span></div>
# <div class="de1">    <span class="co1">// validate the index and that row and column are inside the given borders...</span></div>
# <div class="de1">    <span class="kw1">if</span><span class="br0">(</span><span class="sy0">!</span>index.<span class="me1">isValid</span><span class="br0">(</span><span class="br0">)</span> <span class="sy0">||</span> <span class="br0">(</span>m_data.<span class="me1">size</span><span class="br0">(</span><span class="br0">)</span> <span class="sy0">&lt;=</span> index.<span class="me1">row</span><span class="br0">(</span><span class="br0">)</span><span class="br0">)</span> <span class="sy0">||</span> <span class="br0">(</span>columnCount<span class="br0">(</span><span class="br0">)</span> <span class="sy0">&lt;=</span> index.<span class="me1">column</span><span class="br0">(</span><span class="br0">)</span><span class="br0">)</span><span class="br0">)</span></div>
# <div class="de2">        <span class="kw1">return</span> false<span class="sy0">;</span></div>
# <div class="de1"> </div>
# <div class="de1">    <span class="kw1">if</span><span class="br0">(</span>[http://doc.qt.io/Qt.html <span class="kw5">Qt</span>]<span class="sy0">::</span><span class="me2">EditRole</span> <span class="sy0">==</span> role<span class="br0">)</span></div>
# <div class="de1">    <span class="br0">{</span></div>
# <div class="de1">        <span class="co1">// change the value of the model</span></div>
# <div class="de2">        CdDisk disk <span class="sy0">=</span> m_data.<span class="me1">at</span><span class="br0">(</span>index.<span class="me1">row</span><span class="br0">(</span><span class="br0">)</span><span class="br0">)</span><span class="sy0">;</span></div>
# <div class="de1">        <span class="kw1">switch</span><span class="br0">(</span>index.<span class="me1">column</span><span class="br0">(</span><span class="br0">)</span><span class="br0">)</span></div>
# <div class="de1">        <span class="br0">{</span></div>
# <div class="de1">        <span class="kw1">case</span> <span class="nu0">0</span><span class="sy0">:</span></div>
# <div class="de1">            disk.<span class="me1">m_title</span> <span class="sy0">=</span> value.<span class="me1">toString</span><span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span></div>
# <div class="de2">            break<span class="sy0">;</span></div>
# <div class="de1">        <span class="kw1">case</span> <span class="nu0">1</span><span class="sy0">:</span></div>
# <div class="de1">            disk.<span class="me1">m_author</span> <span class="sy0">=</span> value.<span class="me1">toString</span><span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span></div>
# <div class="de1">            break<span class="sy0">;</span></div>
# <div class="de1">        <span class="kw1">case</span> <span class="nu0">2</span><span class="sy0">:</span></div>
# <div class="de2">            disk.<span class="me1">m_genre</span> <span class="sy0">=</span> value.<span class="me1">toString</span><span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span></div>
# <div class="de1">            break<span class="sy0">;</span></div>
# <div class="de1">        <span class="kw1">case</span> <span class="nu0">3</span><span class="sy0">:</span></div>
# <div class="de1">            disk.<span class="me1">m_year</span> <span class="sy0">=</span> value.<span class="me1">toInt</span><span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span></div>
# <div class="de1">            break<span class="sy0">;</span></div>
# <div class="de2">        <span class="br0">}</span></div>
# <div class="de1">        m_data.<span class="me1">changeDisk</span><span class="br0">(</span>index.<span class="me1">row</span><span class="br0">(</span><span class="br0">)</span><span class="sy0">,</span> disk<span class="br0">)</span><span class="sy0">;</span></div>
# <div class="de1"> </div>
# <div class="de1">        <span class="co1">// don't forget to emit the signal dataChanged and to return true</span></div>
# <div class="de1">        emit dataChanged<span class="br0">(</span>index<span class="sy0">,</span> index<span class="br0">)</span><span class="sy0">;</span></div>
# <div class="de2">        <span class="kw1">return</span> true<span class="sy0">;</span></div>
# <div class="de1">    <span class="br0">}</span></div>
# <div class="de1"> </div>
# <div class="de1">    <span class="co1">// in case, no editing was done, return false.</span></div>
# <div class="de1">    <span class="kw1">return</span> false<span class="sy0">;</span></div>
# <div class="de2"><span class="br0">}</span></div>
</div>
Zum Editieren muss auch die Methode '''data()''' modifiziert werden:
<div class="cpp-qt geshi">
# <div class="de1">[http://doc.qt.io/QVariant.html <span class="kw5">QVariant</span>] CdModel<span class="sy0">::</span><span class="me2">data</span><span class="br0">(</span><span class="kw4">const</span> [http://doc.qt.io/QModelIndex.html <span class="kw5">QModelIndex</span>] <span class="sy0">&amp;</span>index<span class="sy0">,</span> <span class="kw4">int</span> role<span class="br0">)</span> <span class="kw4">const</span></div>
# <div class="de1"><span class="br0">{</span></div>
# <div class="de1">    <span class="kw1">if</span><span class="br0">(</span><span class="sy0">!</span>index.<span class="me1">isValid</span><span class="br0">(</span><span class="br0">)</span><span class="br0">)</span></div>
# <div class="de1">        <span class="kw1">return</span> [http://doc.qt.io/QVariant.html <span class="kw5">QVariant</span>]<span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span></div>
# <div class="de2"> </div>
# <div class="de1">    <span class="kw1">if</span><span class="br0">(</span><span class="br0">(</span>[http://doc.qt.io/Qt.html <span class="kw5">Qt</span>]<span class="sy0">::</span><span class="me2">DisplayRole</span> <span class="sy0">==</span> role<span class="br0">)</span> <span class="sy0">||</span> <span class="br0">(</span>[http://doc.qt.io/Qt.html <span class="kw5">Qt</span>]<span class="sy0">::</span><span class="me2">EditRole</span> <span class="sy0">==</span> role<span class="br0">)</span><span class="br0">)</span></div>
# <div class="de1">    <span class="br0">{</span></div>
# <div class="de1">        ...</div>
# <div class="de1">    <span class="br0">}</span></div>
# <div class="de2"> </div>
# <div class="de1">    <span class="kw1">return</span> [http://doc.qt.io/QVariant.html <span class="kw5">QVariant</span>]<span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span></div>
# <div class="de1"><span class="br0">}</span></div>
</div>

Revision as of 13:56, 25 February 2015

←Teil 1: Table Modell
↑Übersicht Model/View Tutorial:CD Verwaltung↑
Teil 2: Delegate und View→

Ein Modell, dessen Werte editiert werden können

Damit Werte in einem Modell editiert werden können, muss die Methode flags(…) überschrieben werden und für alle editierbaren Zellen auch das flag Qt::ItemIsEditable zurückliefern. Außerdem muss die Methode setData überschrieben werden, da diese von der View aufgerufen wird, um Werte in das Modell zu schreiben.

Wenn die Methode setData() überschrieben wird, muss nach dem Ändern der Werte das Signal dataChanged() explizit ausgelöst werden. Bleibt das Signal aus, dann fehlt den mit dem Modell verbundenen Views der Impuls, ihren Zustand aktualisieren.

Es sind also diese beiden virtuellen Funktionen zu überschreiben:

  • Qt::ItemFlags flags(const QModelIndex& index ) const
  • bool setData(const QModelIndex& index, const QVariant& value, int role)

Im folgenden wird deren Implementierungen beschrieben

flags

Die Methode flags() [doc.qt.nokia.com] wird benutzt, wenn man Eigenschaften eines Modell-Elements ändern möchte. Die am häufigsten benötigten sind:

Wert Beschreibung
Qt::ItemIsSelectable Das Element kann selektiert werden (Standard).
Qt::ItemIsEditable Das Element kann editiert werden.
Qt::ItemIsUserCheckable Das Element kann (üblicherweise mittels einer Checkbox) angekreuzt werden.
Qt::ItemIsEnabled Der Benutzer kann mit dem Element interagieren (Standard).

Wird für ein Element Qt::ItemIsUserCheckable zurückgegeben, wird bei setData auch die Rolle Qt::CheckStateRole übergeben.

In unserem einfachen Beispiel kann jedes Element editiert werden:

  1. Qt::ItemFlags CdModel::flags(const QModelIndex& index ) const
  2. {
  3.     if(index.isValid())
  4.         return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable;
  5.  
  6.     return QAbstractItemModel::flags(index);
  7. }

setData

Die Methode setData [doc.qt.nokia.com] wird von der View (bzw. eigentlich dem Delegate, siehe später) aufgerufen, um die Werte zu setzen. Es können all die Werte gesetzt werden, die mittels data() auch gelesen werden können. Als erstes müssen die Übergabeparameter validiert (= auf ihre Gültigkeit geprüft werden) werden. Dann muss die Rolle überprüft und die Werte im Datenmodell geändert werden. Abschließend muss das Signal dataChanged ausgelöst werden. Wird das vergessen, wird die Datenänderung nicht in der View angezeigt.

Sollte ein Editiervorgang nicht klappen, muss die Methode false zurückliefern, ansonsten true.

In unserem einfachen Beispiel verwenden wir die folgende Implementierung:

  1. bool CdModel::setData(const QModelIndex& index, const QVariant& value, int role)
  2. {
  3.     // validate the index and that row and column are inside the given borders...
  4.     if(!index.isValid() || (m_data.size() <= index.row()) || (columnCount() <= index.column()))
  5.         return false;
  6.  
  7.     if(Qt::EditRole == role)
  8.     {
  9.         // change the value of the model
  10.         CdDisk disk = m_data.at(index.row());
  11.         switch(index.column())
  12.         {
  13.         case 0:
  14.             disk.m_title = value.toString();
  15.             break;
  16.         case 1:
  17.             disk.m_author = value.toString();
  18.             break;
  19.         case 2:
  20.             disk.m_genre = value.toString();
  21.             break;
  22.         case 3:
  23.             disk.m_year = value.toInt();
  24.             break;
  25.         }
  26.         m_data.changeDisk(index.row(), disk);
  27.  
  28.         // don't forget to emit the signal dataChanged and to return true
  29.         emit dataChanged(index, index);
  30.         return true;
  31.     }
  32.  
  33.     // in case, no editing was done, return false.
  34.     return false;
  35. }

Zum Editieren muss auch die Methode data() modifiziert werden:

  1. QVariant CdModel::data(const QModelIndex &index, int role) const
  2. {
  3.     if(!index.isValid())
  4.         return QVariant();
  5.  
  6.     if((Qt::DisplayRole == role) || (Qt::EditRole == role))
  7.     {
  8.         ...
  9.     }
  10.  
  11.     return QVariant();
  12. }