Seite 1 von 1

[gelöst] QStandardItemModel, QTableView, Delegate = Mist

Verfasst: 8. April 2008 20:33
von pfotenpo
Hallo,

also ich habe ein QTableView - Tabelle und unterfüttere diese mit einem QStandardItemModel (myModel). Alles gut.
Nun habe ich mir noch eigene Delegates gebastelt und füge diese wenn gebraucht in die entsprechende Zeile. Auch das klappt gut.
Sagen wir ich habe in Zeile 1 also delegate1. Und in Zeile 2 delegate2. Das Problem ist folgendes: wenn ich Zeile 1 lösche ( myModel->removeRow(1) ) dann rutscht Zeile 2 ja automatisch eins nach oben und wird für den User zur Zeile 1. Leider ist in dieser Zeile aber weiterhin delegate1. delegate2 ist sozusagen nicht mit hochgerutscht!!

HILFE!!

Verfasst: 9. April 2008 00:08
von solarix
Ohne jetzt da viel Erfahrung zu haben, wage ich mal zu behaupten, dass dies auch gar keine Rolle spielt. Denn jede Operation auf das Model (setModelData, setEditorDate) bezieht sich ja auf den Index (es gibt also IMHO keine Kopplung an eine bestimmte Zeile im Model).

Was genau funktioniert denn nicht? Was erwartest/bekommst du?

Verfasst: 9. April 2008 00:28
von pfotenpo
Ja. So seh ich das auch. Es gibt beim Model keine bestimmte Bindung an eine Zeile. Sondern nur an einen Index.
Das/der Delegate hat allerdings eine Bindung zu einer bestimmten Zeile!! Und naja....genau da ist das Problem....wenn ich eine Zeile lösche (diese lösche ich ja im Model und nicht im QTableView) sind die Daten zwar weg, aber das Delegate was ich für diese Zeile im QTableView gesetzt habe ist noch da....und das will ich nicht.
Sondern ich will folgendes: ich habe für Zeile 1 ein Delegate1 im QTableView gesetzt. Für Zeile 2 Delegate2. Wenn ich Zeile 1 nun lösche (aus dem Model) ist das Delegate 1 immer noch in der 1. Zeile, nur leider stehen in dieser ja nun die Daten aus Zeile 2, weil die ja nun eins hoch gerutscht sind.
Drück ich mich verständlich aus? Mach ich irgendwas grundlegend falsch? Ich versteh ja, dass die Dinge so passieren, wie sie passieren. Aber ich will das die Delegates fest mit den daruter liegenden Daten verankert sind und sich quasi mitbewegen wenn sich Zeilen innerhalb des QTableViews verschieben!!

Es ist zum Mäusemelken.

Verfasst: 9. April 2008 09:07
von upsala
Da du das Delegate selbst schreibst, würde ich nicht 2 Verschiedene Delegates schreiben sondern nur eines und dies in Abhängigkeit des Zelleninhaltes (UserRole+x) reagieren lassen.

Verfasst: 9. April 2008 09:10
von solarix
ich versteh immer noch nicht, was an Delegate1 in Zeile 1 nach dem löschen von Zeile 2 verkehrt sein soll.. Zeigt das Delegate den alten Inhalt (den Inhalt der gelöschten Zeile) an? Falls ja, hast du vielleicht das Model abgeleitet und "removeRow()" neu implementiert?

[edit]
Meinst du mit "delegate1"/"delegate2" zwei Instanzen der gleichen Delegate-Klasse (so habe ich es bisher verstanden) oder zwei unterschiedliche Klassen?

Verfasst: 9. April 2008 09:54
von pfotenpo
@solarix: mit delegate1/delegate2 meine ich zwei Instanzen unterschiedlicher Klassen. Sorry wenn das bisher noch nicht rauskam. Und genau...nach dem Löschen von Zeile 1 rutscht Zeile 2 im QTableView ja nach oben. Das Delegate aber, zeigt den alten Inhalt (den der gelöschten Zeile an!)

@upsala: das wär natürlich nicht schlecht wenn ich das hinbekommen würde. Aber das schaff ich nicht. Ich bekomme das glaub ich mit den UserRoles nicht hin. Das übersteigt meine Fähigkeiten (als nicht Informatiker) + ich will ja jedesmal auch Unter- und Obergrenzen für eine sich öffnenedes SpinboxDelegate bzw. die Inhalte eines ComboboxDelegates festlegen. Diese Daten nehme ich aus den nebenstehenden Spalten wenn ich ein Delegate öffnen will.

--> Ich habe mir also ein SpinboxDelegate und ein ComboboxDelegate selber geschrieben und noch eine Methode implementiert mit der ich meine gewünschten Werte in das Delegate registrieren kann.

Hier mal so ein klein wenig Code. Verwenden tue ich die delegates wie folgt:

Code: Alles auswählen

if(x)
{
    ComboBoxDelegate* delegate = new ComboBoxDelegate();
    delegate->registerValues(QStringList() <<"Item1" << "Item2");
    tableView->setItemDelegateForRow(row, delegate);
}

if(y)
{
    SpinBoxDelegate* delegate = new SpinBoxDelegate();
    delegate->registerValues(min, max);
    tableView->setItemDelegateForRow(row, delegate);
}
Die Delegates habe ich ganz normal wie im "SpinBox-Delegate Example" des Qt Tutorials gesubclasst. Einzig die registerValues()-Methode stammt von mir. Die legt einfach den Inhalt der ComboBoxen und die Ober- und Untergrenze der SpinBoxen fest.

Code: Alles auswählen

//ComboBoxDelegate.cpp (Auszug)

//Registrierung der Werte
void ComboBoxDelegate::registerValues (const QStringList& _values)
{
    values = _values;
}

//Hinzufügen der Werte in die ComboBox
QWidget* ComboBoxDelegate::createEditor ( QWidget *parent,
    const QStyleOptionViewItem &/* option */,
    const QModelIndex &/* index */ ) const
{
    QComboBox *editor = new QComboBox(parent);
    editor->addItems(values);
    return editor;
}
Für die SpinBox seiht der Code entsprechend ähnlich aus. Hat noch jemand eine Idee?

@upsala: Kannst du mir mal ein Beispiel bezüglich der UserRoles geben? Aus der Doku werde ich nicht schlau :?

Verfasst: 9. April 2008 12:27
von upsala
Item befüllen:

Code: Alles auswählen

QStandardItem *item;
item->setData(typ, Qt::UserRole+1);
item->setData(minWert, Qt::UserRole+2);
item->setData(maxWert, Qt::UserRole+3);
Und im Delegate wieder auslesen:

Code: Alles auswählen

void Delegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
 int typ=index.data(Qt::UserRole+1).toInt();
 double minWert=index.data(Qt::UserRole+2).toDouble();
 double maxWert=index.data(Qt::UserRole+3).toDouble();
 ...
}

Verfasst: 10. April 2008 16:01
von pfotenpo
@upsala: DANKE! ich habe es so versucht wie du geschildert hast. sprich:

Code: Alles auswählen

QStandardItem* item = new QStandardItem();
item->setData(2, Qt::UserRole+1); // 2 entspricht später der SpinBox
item->setData(min, Qt::UserRole+2); //hier übergeb ich meinen Minimalwert
item->setData(max, Qt::UserRole+3); //hier übergeb ich meinen Maximalwert
myModel->setItem(row,column,item); //hier setz ich das Item für mein Model
im delegate code selbst greife ich dann auf die jeweiligen UserRoles zu:
Beispielauszug aus" delegate.cpp"

Code: Alles auswählen

QWidget* C_delegate::createEditor ( QWidget *parent,
    const QStyleOptionViewItem &/* option */,
    const QModelIndex & index ) const
{
    int type = index.data(Qt::UserRole+1).toInt();
    if(type == 1)
    {
        QComboBox *editor = new QComboBox(parent);
        editor->addItems(index.data(Qt::UserRole+4).toStringList());
        return editor;
    }
    if(type == 2)
    {
        QSpinBox *editor = new QSpinBox(parent);
        editor->setMinimum (index.data(Qt::UserRole+2).toInt());
        editor->setMaximum (index.data(Qt::UserRole+3).toInt());
        return editor;
    }
}
Es klappt dann und auch wenn ich Zeilen aus dem Model lösche, öffnet sich bei Doppelklick jeweils das richtige Delegate. DANKE nochmal!