QT: Wie kopple ich am besten meine individuellen Objekte an QStandardItem ?



  • Also ich benütze QTreeView zum anzeigen und QStandardItemModel als model

    Die Items werden mit QStandardItem angelegt. Und können childs haben. Mehrfachauswahl möglich. Nun mit diesen Items alleine kann ich gar nichts anfangen damit.

    Ich habe eigene Objekte mit class erzeugt, die ebenfalls child und parent haben. Nun überlege wie ich das zusammen mit QStandardItem zusammenbringe. Parents und child müssen synchronisiert sein. Das ist glaube ich zuviel arbeit.

    Dann entdeckte ich noch

    void QStandardItem::setData ( const QVariant & value, int role = Qt::UserRole + 1 ) [virtual]
    

    und

    void QVariant::setValue ( const T & value )
    

    Dachte ich nun, mit templates könnte ich meine klasse da templaten.

    http://doc.qt.nokia.com/latest/qvariant.html#setValue

    Doch das hier funktioniert nicht:

    QVariant v;
    	Object o; // <- mein objekt!
    	v.setValue(o); <- funktioniert nicht
    

    Fehlerausgabe:

    mainwindow.cpp
    1>c:\qt\2010.05\qt\include\qtcore\../../src/corelib/kernel/qmetatype.h(222): error C2039: 'qt_metatype_id': Ist kein Element von 'QMetaTypeId<T>'
    1>          with
    1>          [
    1>              T=Object
    1>          ]
    1>          c:\qt\2010.05\qt\include\qtcore\../../src/corelib/kernel/qmetatype.h(222): Bei der Kompilierung der  Klassen-template der int QMetaTypeId2<T>::qt_metatype_id(void)-Memberfunktion
    1>          with
    1>          [
    1>              T=Object
    1>          ]
    1>          c:\qt\2010.05\qt\include\qtcore\../../src/corelib/kernel/qmetatype.h(232): Siehe Verweis auf die Instanziierung der gerade kompilierten Klassen-template "QMetaTypeId2<T>".
    1>          with
    1>          [
    1>              T=Object
    1>          ]
    1>          c:\qt\2010.05\qt\include\qtcore\../../src/corelib/kernel/qvariant.h(467): Siehe Verweis auf die Instanziierung der gerade kompilierten Funktions-template "int qMetaTypeId<T>(T *)".
    1>          with
    1>          [
    1>              T=Object
    1>          ]
    1>          c:\qt\2010.05\qt\include\qtcore\../../src/corelib/kernel/qvariant.h(533): Siehe Verweis auf die Instanziierung der gerade kompilierten Funktions-template "void qVariantSetValue<T>(QVariant &,const T &)".
    1>          with
    1>          [
    1>              T=Object
    1>          ]
    1>          mainwindow.cpp(178): Siehe Verweis auf die Instanziierung der gerade kompilierten Funktions-template "void QVariant::setValue<Object>(const T &)".
    1>          with
    1>          [
    1>              T=Object
    1>          ]
    1>
    1>Fehler beim Erstellen
    

    Es hat was mit QMetaType zu tun. Wie krieg ich das zum funktionieren? Oder gibt es einen besseren Ansatz?



  • Ich würde vermuten, dass die Doku die du verlinkt hast schon alles zu dem Thema sagt. Woher soll denn QVariant bzw. QMetaType wissen was sie mit deinem Object anfangen sollen. Die Doku beschreibt ja, dass wenn beide Klassen den Typ nicht kennen den sie da bekommen ein Compiler-Fehler erzeugt wird.



  • das klingt irgendwie eher danach, das du von QAbstractItemModel ableiten solltest und intern pointer/referenzen auf deine Objekte speichern solltest. Beispiel:

    http://doc.qt.nokia.com/latest/itemviews-simpletreemodel.html - statt in TreeItem eine QList<QVariant> itemData; zu halten welche die Daten enthält, merkst du dir die ObjektReferenz/Pointer und überlädst QVariant TreeItem::data(int column) const und QVariant TreeModel::data(const QModelIndex &index, int role) const so, dass das richtige zurückgegeben wird. Das verlinkte Beispiel ist readOnly - klick dich durch die passenden Examples ( http://doc.qt.nokia.com/latest/examples-itemviews.html ) und du bekommst evtl ein ReadWrite zu sehen - oder lies dich hier schlauer:

    http://doc.qt.nokia.com/4.7-snapshot/qabstractitemmodel.html#details
    http://doc.qt.nokia.com/4.7-snapshot/qabstractitemmodel.html#subclassing
    http://doc.qt.nokia.com/4.7-snapshot/model-view-programming.html#model-subclassing-reference

    hth



  • Okay, an eine Vererbung dachte ich auch, nur stelle ich mir das zu kompliziert vor. Wie reimplementiere ich das?

    QModelIndex QStandardItemModel::index(int row, int column, const QModelIndex &parent) const
    {
        Q_D(const QStandardItemModel);
        QStandardItem *parentItem = d->itemFromIndex(parent);
        if ((parentItem == 0)
            || (row < 0)
            || (column < 0)
            || (row >= parentItem->rowCount())
            || (column >= parentItem->columnCount())) {
            return QModelIndex();
        }
        return createIndex(row, column, parentItem);
    }
    

    Q_D und d-> versteht der Compiler nicht.

    Irgendwas fehlt mit Q_DECLARE_PRIVATE(QStandardItem)

    Schließlich möchte ich ja, dass die weiterhin so funktionieren wie standardmäßig von Qt.



  • Du schaust in das Beispiel das ich verlinkt habe? Und liest den Kram über Model/View? Und schaust dir die QModelIndex API an?



  • padreigh schrieb:

    Du schaust in das Beispiel das ich verlinkt habe? Und liest den Kram über Model/View? Und schaust dir die QModelIndex API an?

    Ziemlich viel Stoff. Je mehr ich lese umso mehr verliere ich wieder den Überblick.

    diese Lösung hier ist viel einfacher gewesen:
    http://doc.qt.nokia.com/latest/qmetatype.html#Q_DECLARE_METATYPE

    Ich würde schon gerne vererben.
    Sicher dass wenn ich dieses Beispiel nehme, nicht auch noch kopieren und ziehen durch Drag&Drop mit Mehrfachauswahl, sort-Methode etc alles neu implementieren muss? Eine Ableitung versuchte ich mit QStandardItemModel und QStandardItem aber das ist wieder misslungen...

    weil geerbte QStandardItemModel zeigt QStandardItem an, aber keine geerbten QStandardItem. Und umgekehrt zeigt geerbte QStandardItem nur in QStandardItemModel an. Vlt weil Konstruktoren leer sind, und wenn ich nachlese aber nichts finde über subclassing von QStandardItemModel, verliere ich wieder bock... Und sicher dass die Beispiele von dir ihre Mechanismen genauso funktionieren wie die Standards von Qt? Ist ja nur eine Frage, hatte immer das Gefühl dass die anders funktionieren und weniger flexibel.

    Qt ist meine erste Bibliothek und ist noch Fremdkörper



  • Wenn du das hinbekommen hast ohne eigenes Model, gut - dann brauchst du wohl nicht mehr flexibilität als QStandardItemModel dir bietet 🙂 be happy and code on.



  • Ganz schön hart das ganze. Beim drag&drop kommt immer

    "ASSERT failure in QVariant::save: "Invalid type to save", file kernel\qvariant.cpp, line 2035"

    raus. Habe herausgefunden dass es an QMetaType::save liegt

    beide müssen vorhanden sein:

    qRegisterMetaType<Object>("Object");
    	qRegisterMetaTypeStreamOperators<Object>("Object");
    

    http://doc.qt.nokia.com/latest/qmetatype.html#qRegisterMetaTypeStreamOperators

    was muss ich da drinnen einbauen?

    QDataStream &operator<<(QDataStream &out, const MyClass &myObj);
     QDataStream &operator>>(QDataStream &in, MyClass &myObj);
    

    über QDataStream kann ich wiederrum nur int, double und so'n Zeug liefern oder was?



  • ... Grundlagen ...

    Das von dir verlinkte Beispiel sagt:

    // machst du
        qRegisterMetaTypeStreamOperators<MyClass>("MyClass");
    // brauchst du
        QDataStream &operator<<(QDataStream &out, const MyClass &myObj);
        QDataStream &operator>>(QDataStream &in, MyClass &myObj);
    

    Du machst

    qRegisterMetaType<Object>("Object");
        qRegisterMetaTypeStreamOperators<Object>("Object");
    

    also was brauchst du? Wir mal einen Blick hier in die FAQ und ins Magazin, da gibts Artikel über Templates.



  • tschuldigung

    also hier drinnen steht http://doc.qt.nokia.com/latest/qmetatype.html#save

    The type must have been registered with qRegisterMetaType() and qRegisterMetaTypeStreamOperators() beforehand.

    Das beide vorhanden sein müssen, so verstehe ich das

    ich gehe davon aus dass die Funktion bool QMetaType::save aufgerufen wird wenn man in QTreeView Items mit QVariants draggen&droppen tut.

    Jetzt müssen diese streams "<<" und ">>" irgendwie funktionieren.

    Diese Operatoren müssen in meiner Klasse überladen sein, denk ich mal. Nun, QDataStream. Es handelt sich scheinbar um Serialization? Ich kenne mich da nicht aus. Aber müsste ich da jetzt alle Werte aus der Klasse in bekannten Variablen zerlegen und rüberschicken? Kann irgendwie nicht sein oder?



  • padreigh schrieb:

    also was brauchst du? Wir mal einen Blick hier in die FAQ und ins Magazin, da gibts Artikel über Templates.

    ist das hier gemeint? http://www.c-plusplus.net/forum/282091



  • eher http://www.c-plusplus.net/forum/133193 c++ dann das letzte davon: http://www.c-plusplus.net/forum/232010 Eigentlich willst du doch deine Objecte von View "A" nach View "B" schicken, oder? Und das ganze aus einem View "A" welches auf einem QStandardItemModel operiert? Dem du als UserData einen Pointer auf dein Objekt mitgegeben hast?



  • erklärt leider nicht viel

    ich weiss immer noch nicht was das ist:
    std::ostream& X::outputToStream(std::ostream&) const;
    und was ist mit
    std::istream& operator>>(std::istream& lhs, X& rhs); ?

    soll das ganze so aussehen?

    QDataStream &operator<<(QDataStream &out, const Object &Obj)
    {
    	out << Obj.x() << Obj.y() << [weitere werte...];
    	qDebug() << "ausgabe" << out;
    	return out;
    }
    

    bei solchen versuchen kommen bei der ausgabe nur QVariant( ,) raus ?



  • Das sagt dir nix, weil dir GRUNDLAGEN fehlen . Das hat nix mit Qt zu tun, sondern mit C++, API lesen usw.

    So gehts ( du schuldest mir 2h coden 😛 ) und jfye: kein pimpln, kein Ableiten, nix. Nur Anwenden was in der API steht.

    SIMWOODND StandardItemModelWithOwnObjectDragNDrop

    #-------------------------------------------------
    # Project created by QtCreator 2011-03-18T20:52:29
    #-------------------------------------------------
    TARGET = SIMWOODND
    TEMPLATE = app
    
    SOURCES += main.cpp    ds.cpp
    HEADERS += ds.h
    

    main.cpp

    #include <QtGui/QApplication>
    #include "ds.h"
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        DS w;
        w.show();
        return a.exec();
    }
    

    ds.h

    #ifndef DS_H
    #define DS_H
    
    #include <QtGui/QWidget>
    #include <QtCore/QMetaType>
    #include <QtCore/QModelIndex>
    
    class QLabel;
    class QStandardItemModel;
    class QTreeView;
    class QMouseEvent;
    
    class MyOb {
        int val;
    public:
        MyOb(int v = 0) : val(v) {}
        MyOb(const MyOb &ref)
        {
            this->val = ref.val;
        }
    
        ~MyOb() {}
    
        MyOb & operator=(const MyOb & ref)
        {
            this->val = ref.val;
            return *this;
        }
    
        int value() const { return val;}
        int setValue(int v) { val = v; }
    
        typedef MyOb* MyObPointer;
    
    };
    Q_DECLARE_METATYPE(MyOb)
    
    namespace {
        QDataStream &operator<<(QDataStream &out, const MyOb &myObj)
        {
            out << myObj.value();
            return out;
        }
    
        QDataStream &operator>>(QDataStream &in, MyOb &myObj)
        {
            int val;
            in >> val;
            myObj.setValue(val);
            return in;
        }
    }
    
    class DS : public QWidget
    {
        Q_OBJECT
    
    public:
        DS(QWidget *parent = 0);
        ~DS();
    
    private slots:
        void outputMyObDataA(const QModelIndex &);
        void outputMyObDataB(const QModelIndex &);
    
    private:
        QTreeView * viewA;
        QTreeView * viewB;
        QStandardItemModel * modelA;
        QStandardItemModel * modelB;
        QLabel * labA;
        QLabel * labB;
    };
    
    #endif // DS_H
    

    ds.cpp

    #include "ds.h"
    
    // faul
    #include <Qt>
    #include <QtCore>
    #include <QtGui>
    
    const int MyObRole = Qt::UserRole+1234;
    namespace MyTools {
        void initRandomness()
        {
            static bool init(false);
            if (!init)
            {
                qsrand(QTime(0,0,0,0).msecsTo(QTime::currentTime()));
                init = true;
            }
        }
    
        void fill(QStandardItemModel * model)
        {
            initRandomness();
    
            QStandardItem *item=0;
            QStandardItem *parent=0;
            QVector<QStandardItem*> all;
            while(all.size()<100)
            {
                item = new QStandardItem(QString("____%1").arg(QString::number(all.size())).right(5));
                MyOb my = MyOb(all.size());
    
                QVariant myVariant;
                myVariant.setValue(my);
    
                item->setData(myVariant,MyObRole);
                {
                    // 1 in 3 add it to existing one
                    if ( (! (qrand()%3) ) && (! (all.isEmpty()) ) )
                    {
                        int pos = qrand() % all.size();
                            all[pos]->appendRow(item);
                    }
                    else
                    {
                        model->appendRow(item);
                    }
                }
                all.push_back(item);
            }
        }
    };
    
    DS::DS(QWidget *parent)
        : QWidget(parent)
    {
        QGridLayout * lay = new QGridLayout(this);
        {
            viewA = new QTreeView(this);
            {
                viewA->setDragEnabled(true);
                viewA->setDragDropMode(QAbstractItemView::DragDrop);
                viewA->setDefaultDropAction(Qt::MoveAction);
                viewA->setDragDropOverwriteMode(false);
                modelA = new QStandardItemModel(this);
                MyTools::fill(modelA);
                viewA->setModel(modelA);
            }
            lay->addWidget(viewA,0,0);
    
            viewB = new QTreeView(this);
            {
                viewB->setDragEnabled(true);
                viewB->setDragDropMode(QAbstractItemView::DragDrop);
                viewB->setDefaultDropAction(Qt::MoveAction);
                viewB->setDragDropOverwriteMode(false);
                modelB = new QStandardItemModel(this);
                viewB->setModel(modelB);
            }
            lay->addWidget(viewB,0,1);
    
            labA = new QLabel("-",this);
            lay->addWidget(labA,1,0);
    
            labB = new QLabel("-",this);
            lay->addWidget(labB,1,1);
    
            connect(viewA,SIGNAL(clicked(QModelIndex)),this,SLOT(outputMyObDataA(QModelIndex)));
            connect(viewB,SIGNAL(clicked(QModelIndex)),this,SLOT(outputMyObDataB(QModelIndex)));
    
            qRegisterMetaTypeStreamOperators<MyOb>("MyOb");
        }
    }
    
    DS::~DS(){}
    
    void DS::outputMyObDataA(const QModelIndex &index)
    {
        QVariant v = viewA->model()->data(index,MyObRole);
        if (v.canConvert<MyOb>())
        {
            MyOb o = v.value<MyOb>();
            labA->setNum(o.value());
        }
        else labA->setText("-");
    }
    
    void DS::outputMyObDataB(const QModelIndex &index)
    {
        QVariant v = viewB->model()->data(index,MyObRole);
        if (v.canConvert<MyOb>())
        {
            MyOb o = v.value<MyOb>();
            labB->setNum(o.value());
        }
        else labB->setText("-");
    }
    


  • hm eine katastrophe für mich

    Dann ist das was ich in &operator<< geschrieben habe, schon richtig gewesen.
    Nur leider nix gepeilt, dass das hier nichts brachte: qDebug() << out;

    So stand ich auf dem Schlauch und dachte dass auch bei der Ausgabe nicht funktionieren wird. Wenn das jetzt an Grundlagen liegt... 😕

    Für %operator>> also nur noch das

    in >> x >> y;
    Obj.setX(x); Obj.setY(y);

    aber interessant der code

    ( du schuldest mir 2h coden 😛 )

    dann merk ich mir das ^^



  • qDebug() ist doch ein VÖLLIG anderer Stream als der QDataStream .... liest du QDebug API: http://doc.qt.nokia.com/latest/qdebug.html#details siehste http://doc.qt.nokia.com/latest/qdebug.html#writing-custom-types-to-a-stream guckste da und siehst

    QDebug operator<<(QDebug dbg, const Coordinate &c)
     {
         dbg.nospace() << "(" << c.x() << ", " << c.y() << ")";
    
         return dbg.space();
     }
    

    für Coordinate &c .. du brauchst das für dein Objekt ... das ganze als Freie Funktion und feddich - dann kannst du dein Object über qDebug() << meinObjekt; ausgeben.

    Poste bitte mal deinen Object Code.



  • Ja hab ich schon verstanden. Also gut ich poste mal ein paar Codes.
    Mein Ziel ist, mein Programm soll ein Objekt-Manager haben, mit Attributen-Fenster für die Objekte. Und ein CentralWidget. Das Konzept ist ein bißchen ähnlich wie aus dem Programm Cinema4D.

    Fügt man ein Objekt hinzu, taucht sie auf, plus im CentralWidget eine grafische Darstellung. Objekte sollen dann abgeleitet werden in Null-Objekt, Kreis-Objekt, Wellengenerator etc...
    Dann soll ein einzelnes Objekt ein Vector mit Zeigern auf andere Objekte zeigen können. (für spezielle Einflüsse) Über Attributen-Fenster sollen die Objekte gesteuert werden.

    Sie sollten gegenseitig Einflüsse haben. Mit Schwerkräften u.ä. sollen sie sich bewegen. Alles wird im Thread berechnet. Ich denke die Framebremse krieg ich hin.

    object.h

    #ifndef _OBJECT_
    #define _OBJECT_
    
    #include <QtGui>
    //#include <QVector>
    
    class Object
    {
    public:
    //	Object();
    	Object(Object* parent = 0, int x = 0, int y = 0);
    	~Object();
    
    	Object & operator=(const Object & ref)
        {
            this->getX = ref.getX;
    		this->getY = ref.getY;
            return *this;
        }
    
    	int id() const;
    	//QVector<Growth*>& gvector() const;
    
    	int x() const;
    	int y() const;
    	void setX(int value);
    	void setY(int value);
    	Object* parent() const;
    	Object* child() const;
    
    private:
    	int getX, getY, getId;
    	Object *getParent, *getChild;
    };
    
    	QDataStream &operator<<(QDataStream &out, const Object &Obj);
        QDataStream &operator>>(QDataStream &in, Object &Obj);
    
    Q_DECLARE_METATYPE(Object)
    
    #endif // _OBJECT_
    

    object.cpp

    #include "object.h"
    #include <QDebug>
    
    unsigned int idnum = 0;
    /*Object::Object() 
    {
    	getX = getY = 0;
    	getParent = 0;
    	qDebug() << "created constructor 1";
    }*/
    
    Object::Object(Object* parent, int x, int y) 
    	   : getParent(parent) , getX(x), getY(y)
    {
    	getId = idnum++;
    	getChild = NULL;
    	if (!getParent) getParent = this;	// Wenn dieses Objekt keine Eltern hat, dann sind sie Eltern selbst.
    	qDebug() << "created object id:" << getId;
    }
    
    Object::~Object()
    {
    	qDebug() << "destructor object activated from" << getId;
    }
    
    int Object::id() const 
    {
    	return getId;
    }
    
    void Object::setX(int value)
    {
    	getX = value;
    }
    
    void Object::setY(int value)
    {
    	getY = value;
    }
    
    int Object::x() const 
    {
    	return getX;
    }
    
    int Object::y() const 
    {
    	return getY;
    }
    
    Object* Object::parent() const 
    {
    
    	return getParent;
    }
    
    Object* Object::child() const 
    {
    
    	return getChild;
    }
    
    QDataStream &operator<<(QDataStream &out, const Object &Obj)
    {
    	out << Obj.x() << Obj.y();
    	return out;
    }
    
    QDataStream &operator>>(QDataStream &in, Object &Obj) 
    {
    	int x, y = 0;
        in >> x >> y; 
    	Obj.setX(x);
    	Obj.setY(y);
    	return in;
    }
    

    main.cpp

    #include "mainwindow.h"
    #include <QtGui/QApplication>
    
    int main(int argc, char *argv[])
    {
    	QApplication a(argc, argv);
    	MainWindow w;
    	w.show();
    	return a.exec();
    }
    

    ich zeig hier ein paar Codeabschnitte aus mainwindow.cpp

    #include "mainwindow.h"
    // Flags
    const int ObjectRole = Qt::UserRole + 1001;
    // App
    MainWindow::MainWindow(QWidget *parent, Qt::WFlags flags)
    	: QMainWindow(parent, flags)
    {
    
    	//model
    
    	qRegisterMetaType<Object>("Object");  // Für QMetaType, damit sie mit der Klasse Object (von mir) funktionieren
    	qRegisterMetaTypeStreamOperators<Object>("Object");	// 
    
    	model = new QStandardItemModel;
    	item = new QStandardItem("Objekte");
    	model->setHorizontalHeaderItem(0, item); 
    	//item = new QStandardItem("Attribute");
    	//model->setHorizontalHeaderItem(1, item);
    
    }
    
    int o_counter = 0; 
    void MainWindow::newObject( ) {
    
    	item = new QStandardItem(QString("Objekt.%0").arg(o_counter+=1));
    	model->appendRow(item);
    
    	Object o;
    	o.setX(1313); //beispielszahlen
    	o.setY(1212); //beispielszahlen
    	QVariant v;
    	v.setValue(o);
    	item->setData(v, ObjectRole);
    
    }
    
    void MainWindow::deleteObject( ) {
    	while (treeWidget->selectionModel()->selectedRows().size() != 0) 
    		model->removeRow( treeWidget->selectionModel()->selectedRows().at(0).row(), 
    					 treeWidget->selectionModel()->selectedRows().at(0).parent() );
    	}
    
    void MainWindow::execFunction2( ) {
    	qDebug() << "Function 2 ausgeführt";
    
    	//Item* dcast;
    	//dcast = dynamic_cast<Item*>(model->item(treeWidget->currentIndex().row()));
    
    	QVariant v = model->data(treeWidget->currentIndex(), ObjectRole);
    	//Object o = v.value<Object>();
    	obj_p = &v.value<Object>();
    	qDebug() << obj_p->x();
    	qDebug() << obj_p->y();
    	qDebug() << obj_p->id();
    
    }
    

    Mir fällt auf dass der Destuktor zu oft aufgerufen wird, wenn ich execFunction ausführe.
    Ich müsste eigentlich ein Zeiger direkt auf Object zeigen. Das v.value<Object>() ist für mich halt noch befremdlich

    virtual QVariant 	data ( const QModelIndex & index, int role = Qt::DisplayRole ) const
    

    ich befürchte dass das gar nicht geht. Vlt hast du recht, also doch vererben. hmm...

    Mit einer richtigen GUI-Befestigung mit Objekt-Manager wollt ich eigentlich richtig C++ lernen anfangen



  • hm ich hatte da die Idee, dass ich nur den Zeiger übergebe

    Q_DECLARE_METATYPE(Object*)

    und

    obj_p = v.value<Object*>();

    aber jetzt funktionieren die streams nicht mehr.

    Müsste ich jetzt eigentlich die nur Speicheradresse übergeben?
    Beim kopieren, dürften die neuen Items aber nicht auf diesselben Objecte zeigen
    Eine gute Idee?



  • Objekt* wird mit dem save/load vom QMetaType vermutlich eher nicht funktionieren - probiers aus. Auf jeden Fall musst du dann Objekt* auch wieder als qMetairgendwas deklarieren, das ist ja <templatemäßig gesehen> ein völlig anderer Typ als Objekt.
    Abgesehen davon hast du noch andere Merkwürdigkeiten und Probleme.

    • Warum prefixed du alle Member mit get?
    • Kann jedes Objekt nur EIN Child haben?
    • Warum ist ein Objekt parent von sich selbst wenn es kein parent hat, warum nicht einfach parent 0 lassen, macht doch die Unterscheidung hatParent viel einfacher?
    • Warum deklarierst du einen default-Construktor und einen operator=() aber keinen Copyconstructor (--> google "C++ Regel der Drei")
    • Warum Kopiert der operator=() nur x und y aber nicht das parent ... die Dinger sollten hinterher wirklich Identisch sein, nicht nur zu 50% ... was ist dabei mit der ID ... sollte der beim Kopieren eine neue ID
      bekommen oder dürfen die IDs mehrfach vorkommen
    • was passiert beim (zu implementierenden) CopyConstructor mit ID und parent
    • Bau mal 3 Objekte hinternander und gib dir die IDs aus
    • Warum packst du deine Objecte überhaupt als Objekt ins TreeModel - die haben doch eine ID, warum nimmste nicht einfach NUR DIE?
    • wenn du von deinem Objekt ableiten willst, warum ist der Destructor nicht virtual

    So als Anregung: Mach dir eine QtConsolen Applikation auf, entwickle dein Object soweit das es funktioniert, nutze als Ausgabe qDebug() und die qDebug() Stream Überladung. Mach dir 3-4 geerbte Objekte auch gleich fertig.

    Statt x und y selber zu verwalten, nutze intern einen QPoint - du kannst ja trotzdem noch 3 getter anbieten:

    private:
      QPoint position;
    public:
    QPoint pos() const { return position; }
    int    x()   const { return position.x(); } 
    int    y()   const { return position.y(); } 
    
    void  setPos(/*const*/ QPoint &p) { position = p; } // lass evtl. das const hier weg, weils für die Schnittstelle uninteressant ist - DU weisst das du das nicht verändern solltest
    void  setX(int x)      { position.setX(x); } 
    void  setY(int y)      { position.setY(y); }
    

    Wenn dein Objekt tut, und du zB so eine Beispielstuktur hast (O == dein Object, Zahl=ID)

    O0
    |-- O1
    |   `-- O6
    |       `-- O8
    |-- O2
    |   `-- O4
    |-- O3
    |   `-- O5
    `-- O9
        |-- 010
        |-- 011
        |   `-- O13
        `-- 012
    

    Was hindert dich daran, deinen QStandardItems im QStandardItemModel die selbe ID zu geben QVariant v(deineID);item->setData(v, ObjectRole); .. dann wirfst du einen Blick in die API von QAbstractItemModel(von dem QStandardItemModel erbt) und findest http://doc.qt.nokia.com/latest/qabstractitemmodel.html#signals ... da gibts sicher welche die dir Sagen wenn sich ein Item ändert oder eingefügt wird oder entfernt wird. Dann schreibst du dir saubere SLOTS die die Aktion auf deine Objekte übertragen. Was genau verschoben wird und wohin, bekommst du über die von dir identisch gesetzten IDs (item->data(ObjektRole) und den QModelIndex raus.

    Ich denke die Framebremse ist dein kleinstes Problem. Genauso wie die graphische Repräsentation 😉 Anspruchsvolles Vorhaben, bei dem du sicher ne Menge lernen wirst.



  • Danke für die ausführlichen Tipps. Das Object hab ich aus meinem anderen Programm kopiert, wo es so nötig war. Werde es natürlich umbauen. Das mit Kopierkonstruktor war mir nicht so bewußt. Ja die ID's sollen nur einmal geben.

    Mit signals meinte ich ja eigentlich was ich im Eingangspost mit "synchronisieren" meinte. Und so wie es ausschaut, gibt auch da Probleme 😞

    int obj_id = 0; 
    void MainWindow::rowsInserted( const QModelIndex & parent, int start, int end ) {
    	qDebug() << parent << "start: " << start << "end: " << end; 
    		for ( ; start <= end; ++start) {
    			qDebug() << start;
    			model->item(start, 0)->setData(obj_id+=1, ObjectRole);
    		}
    }
    

    Beim inserten einzelner Objekte geht es noch. Aber sobald ich die items move oder kopiere, stürzt's immer ab.

    ich kann mit diesen start-end gar nichts anfangen. Wenn ich 5 items erzeuge, alle auswähle und nach unten ziehe (move), hat das signal rowsInserted: start: 5 end: 9 ausgesendet. Zeigt auf Items, die gar nicht existieren, weil die 5 nirgendswo bewegt wurden, weil alle ausgewählt wurden. Auch beim kopieren stürzt's komischerweise ab. Auch Versuche wie if (start < end) i = end-start; schlugen fehl. Der Signal rowsMoved wird gar nicht ausgesendet. Warum gibt es kein Signal, der einfach eine Referenz/Pointer direkt auf Items zurückgibt, welche Objekte eingefügt, bewegt oder gelöscht wurden? Der Signal rowsAboutToBeRemoved wird auch nicht vor rowsMoved ausgesendet. Irgendwie wird alles verwehrt 😞


Anmelden zum Antworten