Seite 1 von 1

QStandardItemModel und QTreeView

Verfasst: 24. Juli 2010 21:08
von dd0815
Hallo liebe Qt-Gemeinde,

ich habe ein paar Startprobleme bei Models und dem TreeView. Ich habe eine Baumstruktur, in der zum einen die Beschreibung des Wertes sowie der Wert (UserRole + 1) abgespeichert wird, hier mein Testcode:

Erst das Model erstellen

Code: Alles auswählen

    // Model erstellen
    QStandardItemModel *commModel = new QStandardItemModel;
    QStandardItem *parentItem = commModel->invisibleRootItem();
    for (int i = 0; i < 4; ++i) {
        QStandardItem *item = new QStandardItem(QString("item %0").arg(i));
        item->setData(QString("data %0").arg(i),Qt::UserRole + 1);
        parentItem->appendRow(item);
        // parentItem = item;

        qDebug() << "gespeicherte Daten: " << item->data(Qt::UserRole + 1);

    }

    commModel->setColumnCount(3);
    commModel->setHeaderData(1, Qt::Horizontal,QVariant("test"),Qt::UserRole + 1);
dann das TreeWidget

Code: Alles auswählen

    QTreeView *commTree = new QTreeView;
    commTree->setModel(commModel);
    // commTree->setHeaderHidden(false);
Hier meine Frage:
Wie kann ich die Werte in der zweiten Spalte anzeigen? Mit "setColumnCount" kann ich zwar mehr Spalten anzeigen, aber die Werte fehlen. Mit "setHeaderData" hats auch nicht funktioniert.

(Das SimpleTreeModel-Beispiel hat mir nicht weitergeholfen, ich kann dort nicht finden, wies funktioniert. Ebenso tagelanges Suchen im Netz und hier)

Einen schönen Abend noch,
::dd0815::

Verfasst: 24. Juli 2010 22:47
von franzf
mit eigener userrole kommst du nicht weiter, das erzeugt dir ja keine neue spalte. setColumnCount hilft auch nix (lies die doku genau durch ;)).
weiter bringt dich das bespiel in der doku zum erzeugen einer table.

Verfasst: 26. Juli 2010 22:12
von dd0815
Hallo franzf,

vielen Dank für die schnelle Antwort. Ich habe mir mittlerweile das Tabellenmodell angeschaut. In einer Tabelle kann ich zwar in einer Reihe beliebig viele QStandardItems anfügen, aber grundsätzlich benötige ich eine Baumstruktur, d.h. nach dem Anlegen folgender Tabellenstruktur habe ich natürlich nicht die benötigte Kind-Eltern Beziehung.

Code: Alles auswählen

    QStandardItemModel *commModel = new QStandardItemModel;
    for (int i = 0; i < 4; ++i) {
        QStandardItem *item = new QStandardItem(QString("item %0").arg(i));
        QStandardItem *itemData = new QStandardItem(QString("data %0").arg(i));
        commModel->setItem(i,i,item);
        commModel->setItem(i,i+1,itemData);
    }
(aber wahrscheinlich habe Dein Hinweis nicht ganz verstanden :( )

Wie gesagt möchte ich im QTreeView sowohl Beschreibung als auch Werte sehen. Die einzige Möglichkeit im QStandardModel Werte abzuspeichern (als QVariant) ist mittels "setData" eines QStandardItems (korrigiert mich falls ich etwas Falsches sage). Das heißt für mich: eigentlich kann ich meine Daten im QTreeView nicht sehen?

muss doch gehen :-),

::dd0815::

Verfasst: 26. Juli 2010 23:58
von forgoden
ich hab das gleiche Problem

im moment schaut mein code so aus:

Code: Alles auswählen

	item = new QStandardItem("Objekte");
	model->setHorizontalHeaderItem(0, item); 
	item = new QStandardItem("Attribute");
	model->setHorizontalHeaderItem(1, item); 

	item = new QStandardItem("Objekt_1");
	model->setItem(0,0,item);
	item = new QStandardItem("data 1");
	item->setDropEnabled(false);
	model->setItem(0,1,item);
dadurch werden in der zweiten Spalte die Werte auch angezeigt, aber man muss jedes mal ein extra QStandardItem erzeugen. Außerdem weiss ich nicht wie man in der zweiten Spalte das droppen verbietet.

Verfasst: 27. Juli 2010 09:17
von franzf
forgoden hat geschrieben:dadurch werden in der zweiten Spalte die Werte auch angezeigt, aber man muss jedes mal ein extra QStandardItem erzeugen.
Und was erwartest du! Wenn du dir ein normales Model zusammen basteln würdest, müsstest du für jede Spalte auch einen eigenen QModelIndex zurückgeben. Und warum sollte das dann bei dem QStandardItemModel anders sein, der als normales QAbstractItemModel die QModelIndex-Schnittstelle anbieten muss?

Und das Table-Example mit dem Wissen (QStandardItemModel::setItem(row, col, item)) sollte es einem ermöglichen, einen tiefen TreeView mit mehreren columns zu bestücken. "Transferaufgabe" - kennt man doch aus der Schule :P

Verfasst: 27. Juli 2010 12:30
von dd0815
Hallo franzf,

bevor ich weiterhin so etwas Schlimmes probieren muss (was nebenbei gesagt nicht funktioniert):

Code: Alles auswählen

    QStandardItem *itemData = new QStandardItem(QString("data1"));
    QList<QStandardItem> *itemList = new QList<QStandardItem>;
    itemList->append(itemData);
    item1->appendColumn(itemList);
    parentItem->setChild(0, item1);
frage ich doch noch mal nach, welches
Table-Example
Du genau meinst? Bis jetzt dachte Du meinst in der Hilfe des Qt SDK (v2010.02.1) den Abschnitt "Framework&Technologies > Model/View Programming > Model Classes". In der Examples & Demos-Applikation hab ich nach dem Durchsuchen auch kein als solches deklariertes Example finden können.

Verfasst: 27. Juli 2010 13:33
von forgoden
vielleicht ist es "simple tree model" in qt demos gemeint?

Verfasst: 27. Juli 2010 13:38
von franzf
Ich dachte an das Beispiel zu QStandardItemModel.
Ich hab das mal schnell in der Pythonkonsole gemacht, wirst es nach C++ transferieren müssen, ist aber eigentlich klar.
Hier ju ar:

Code: Alles auswählen

>>> from PyQt4.Qt import *
>>> app = QApplication([])
>>> model = QStandardItemModel()
>>> view = QTreeView()
>>> view.setModel(model)
>>> root = QStandardItem("Hallo root")
>>> model.appendRow(root)
>>> items = []
>>> items.append(QStandardItem("child"))
>>> items.append(QStandardItem("child 2"))
>>> items.append(QStandardItem("child 3"))
>>> root.appendRow(items)
>>> model.setColumnCount(3)
>>> items = []
>>> hasChildren = QStandardItem("with children")
>>> items.append(hasChildren)
>>> items.append(QStandardItem("col 2"))
>>> items.append(QStandardItem("col 3"))
>>> root.appendRow(items)
>>> items = []
>>> items.append(QStandardItem("next level"))
>>> items.append(QStandardItem("col 2"))
>>> items.append(QStandardItem("col 3"))
>>> hasChildren.appendRow(items)
items = [] definiert einfach ein Array (wg. QList an der Stelle).

Code: Alles auswählen

QList<QStandardItem> *itemList = new QList<QStandardItem>; 
Das machst du bitte sofort in ein

Code: Alles auswählen

QList<QStandardItem*> itemList;
wir sind hier nicht in Java wo alles mit new allokiert werden muss :P

// edit:
Das QStandardItemModel.setItem(row, column, item) funktioniert nur für topLevelItems. Für tiefere Items nimmst du dann QStandardItem.setChild(row, column, child), wenn du es auf diese Weise machen willst.
Ich mach einfach nie was mit QStandardItemModel, das ist echt ein Problem :P

Verfasst: 27. Juli 2010 16:23
von forgoden
okay das ist jetzt nicht viel anders als meine Lösung :D

@dd0815 bevor du hier wegkommst, kannst Du bitte für mich mal testen?
Und zwar einfach
commTree->setDragDropMode(QAbstractItemView::DragDrop);
setzen und mir sagen, ob die Objekte sich kopieren lassen, wenn die nur mit der Maus gezogen werden, oder sich erst dann kopieren lassen wenn die Shift-Taste gedrückt gehalten wird?

Verfasst: 27. Juli 2010 16:46
von dd0815
Hallo franzf,

vielen Dank für Deine Bemühungen. Das Tabellenbeispiel im QStandardItemModel funktioniert ja, nur brauch ich keine Tabelle :-)

So, hier der nächste Wurf:

Code: Alles auswählen

    // Modell erstellen
    QStandardItemModel *commModel = new QStandardItemModel; // Modell erstellen
    QStandardItem *parentItem = commModel->invisibleRootItem(); // Root Item erstellen

    // hier die Items (aber Daten sinds immer noch nicht!!!)
    QStandardItem *item1 = new QStandardItem(QString("item1")); // Child vom Root
    QStandardItem *item1_1 = new QStandardItem(QString("item1_1")); // Child vom Child
    QStandardItem *item1_1Col2 = new QStandardItem(QString("item1_1Col2")); // Spalte 2 vom ChildChild
    QStandardItem *item1_1Col3 = new QStandardItem(QString("item1_1Col3")); // Spalte 3 vom ChildChild

    parentItem->appendRow(item1); // dem Root das Child anhängen
    item1->appendRow(item1_1); // dem Child das Child anhängen
    
    // Spalten vorbereiten
    QList<QStandardItem*> itemList;
    itemList.append(item1_1Col2);
    itemList.append(item1_1Col3);

    // der Versuch, dem Child Spalten anzuhängen (tauchen aber trotzdem als dessen Kinder auf) 
    item1_1->appendColumn(itemList);

    commModel->setColumnCount(3); // 3 Spalten anzeigen
    
    // TreeView erstellen
    QTreeView *commTree = new QTreeView;
    commTree->setModel(commModel);
Wie im Kommentar des Codes erwähnt tauchen "item1_1Col2 und 3" auch nur als Kinder und nicht als Spalten von item1_1 auf...

Selbst wenn es gehen würde, das klärt immer noch nicht die Frage der Daten, die ja nicht als String des Items gespeichert werden sollen...

Im Simple Tree Model gehts doch auch, da gibts 2 Spalten (in der zweiten steht eine Beschreibung). Vielleicht können wir das mal gemeinsam auseinander pflücken, wie man die einzelnen Reihen einfügt...

Bin fast soweit das Model / View programmieren wieder abzuwählen :?

::dd0815::

@forgoden: Moment, ich hab hier noch eine Familie auf dem Hals (hab grad Ferien) ich melde mich später noch mal

Verfasst: 27. Juli 2010 16:51
von franzf

Code: Alles auswählen

item1_1->appendColumn(itemList);
->

Code: Alles auswählen

item1_1->appendRow(itemList);

Verfasst: 27. Juli 2010 19:56
von dd0815
Hallo zusammen,

Schei..., nun funktionierts. Hab die überladene appendRow-Funktion übersehen bzw. mir nun erstmal genau angeschaut.

@forgoden
Für das Kopieren von Items brauche ich nur die Maus, d.h. nach dem Loslassen der linken Maustaste ist die Kopie da.

Für alle, die die Lösung interessiert:

Code: Alles auswählen

    // Modell erstellen
    QStandardItemModel *commModel = new QStandardItemModel; // Modell erstellen
    QStandardItem *parentItem = commModel->invisibleRootItem(); // Root Item erstellen

    // hier die Items (aber Daten sinds immer noch nicht!!!)
    QStandardItem *item1 = new QStandardItem(QString("item1")); // Child vom Root
    QStandardItem *item1_1Col1 = new QStandardItem(QString("item1_1Col1")); // Spalte 1 vom ChildChild
    QStandardItem *item1_1Col2 = new QStandardItem(QString("item1_1Col2")); // Spalte 2 vom ChildChild
    QStandardItem *item1_1Col3 = new QStandardItem(QString("item1_1Col3")); // Spalte 3 vom ChildChild

    parentItem->appendRow(item1); // dem Root das Child anhängen

    // Spalten vorbereiten
    QList<QStandardItem*> itemList;
    itemList.append(item1_1Col1);
    itemList.append(item1_1Col2);
    itemList.append(item1_1Col3);

    item1->appendRow(itemList); // Child an Child hängen

    commModel->setColumnCount(3); // 3 Spalten anzeigen

    // TreeView erstellen
    QTreeView *commTree = new QTreeView;
    commTree->setModel(commModel);
    // commTree->setHeaderHidden(false);
    commTree->setDragDropMode(QAbstractItemView::DragDrop);

    item1_1Col3->setText("Neuer Text"); // mal ein Item ändern
@franzf: Besten Dank für Deine aufopferungsvolle Hilfe...

Bis später,
::dd0815::

P.S. Das waren bisher die höchsten Grundlagen-Hürden bei Qt, jetzt kann endlich programmiert werden :-)

Verfasst: 27. Juli 2010 20:59
von forgoden
dd0815 hat geschrieben: @forgoden
Für das Kopieren von Items brauche ich nur die Maus, d.h. nach dem Loslassen der linken Maustaste ist die Kopie da.
Danke, das scheint Qt-Standard zu sein. So ist es bei mir auch. So ein mist.

Man muss irgendwas mit QDropEvent machen aber kompliziert, kompliziert...