QAbstractItemModel/TreeView zeigt nichts an


  • Mod

    Es soll eine flache Hierachie sein, ja.
    Ein unsichtbares Rootelement, und dann jeweils ein element mit 2 kindern.
    Als erster Test.

    Verstehe deine Änderungen nicht ganz, aber wie gesagt, der Code ist so aus dem Beispiel übernommen...



  • Falls du das addNode(.) benutzt nachdem das Model bereits dem View zugeordnet war, schau mal hier:

    http://doc.trolltech.com/4.1/qabstractitemmodel.html#details unter Subclassing

    Models that provide interfaces to resizable data structures can provide implementations of insertRows(), removeRows(), insertColumns(), and removeColumns(). When implementing these functions, it is important to notify any connected views about changes to the model's dimensions both before and after they occur:

    * An insertRows() implementation must call beginInsertRows() before inserting new rows into the data structure, and it must call endInsertRows() immediately afterwards.
    * An insertColumns() implementation must call beginInsertColumns() before inserting new columns into the data structure, and it must call endInsertColumns() immediately afterwards.

    Ich hatte mir Anfang des Jahres ein TreeModel für ein Interface das Sql-Queries kapselt geschrieben, kann Dienstag mal nachschaun wie ich das dort gemacht habe - mein Startpunkt war auch das SimpleTreeModel Beispiel... allerdings besteht bei mir die komplette Struktur der Tabellen vorher, also keine onthefly Hinzufügen von neuen Einträgen ... ist eine ReadOnly Tabelle im Moment


  • Mod

    So, hab das jetzt mal als Testprojekt zusammengehackt, unter http://codenode.de/TreeModel.zip kann man sich es runterladen.

    Wieso das jetzt nicht klappt ist mir ein Rätsel.
    Vielleicht findet ja jemand den Fehler...



  • Ich bekomme leider nur ein "File Not Found!" beim versuch die Datei downzuloaden.


  • Mod

    guenni81 schrieb:

    Ich bekomme leider nur ein "File Not Found!" beim versuch die Datei downzuloaden.

    Äh, ja. Falscher Ordner. Jetzt klappts.



  • Darf ich nochmal auf

    padreigh schrieb:

    Falls du das addNode(.) benutzt nachdem das Model bereits dem View zugeordnet war, schau mal hier:

    http://doc.trolltech.com/4.1/qabstractitemmodel.html#details unter Subclassing

    Models that provide interfaces to resizable data structures can provide implementations of insertRows(), removeRows(), insertColumns(), and removeColumns(). When implementing these functions, it is important to notify any connected views about changes to the model's dimensions both before and after they occur:

    * An insertRows() implementation must call beginInsertRows() before inserting new rows into the data structure, and it must call endInsertRows() immediately afterwards.
    * An insertColumns() implementation must call beginInsertColumns() before inserting new columns into the data structure, and it must call endInsertColumns() immediately afterwards.

    verweisen? Ich hab 9h Autobahn hinter mir, guck mir den Quelltext morgen mal an und bau das ein um zu sehen obs tut. Ich denke dein addNode geht einfach an QTs Model/View Struktur vorbei, daführ haben die spezielle Methoden vorgesehen die du reimplementieren musst?


  • Mod

    Ja, aber im Beispiel wird das nicht verwendet.
    Es wird ja auch nix angezeigt wenn ich das vorher erstelle.
    Auch ein erneutes setModel bringt nichts.



  • Schwere Nuss .. was ich bisher fand:

    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
        model = new DocumentTreeModel();
        ui->treeView->setModel(model);
    
        qDebug() << "! Startup !";
            model->debugOut();
    }
    
    DocumentTreeModel::DocumentTreeModel(QObject *parent) :
        QAbstractItemModel(parent)
    {
        doc = new DocRoot("Root");
        DocRoot * it1 = new DocRoot("Item A");
        it1->addNode(new DocRoot("Sub1"));
        it1->addNode(new DocRoot("Sub2"));
        doc->addNode(it1);
    }
    
    void DocumentTreeModel debugOut(int lvl=0, DocRoot * dr=0) {
        if (lvl == 0 && dr == 0)
        {
            debugOut(0, doc);
        }
        else {
            qDebug() << QString(lvl*4,' ') << dr->getText();
            foreach(DocRoot *ch, dr->getAllChilds())
                debugOut(lvl+1, ch);
        }
    }
    
    void MainWindow::on_pushButton_clicked()
    {
        static int num = 1;
        QString txt("Item" + QString::number(++num));
        DocRoot* root = new DocRoot(txt);
        root->addNode(new DocRoot(QString(txt+"a")));
        root->addNode(new DocRoot(QString(txt+"b")));
    
        model->addNode(root);
        model->update();
        model->debugOut();
    }
    

    Bringt die Datenstruktur auf

    "" "Root" 
    "    " "Item A" 
    "        " "Sub1" 
    "        " "Sub2" 
    "    " "Item2" 
    "        " "Item2a" 
    "        " "Item2b" 
    "    " "Item3" 
    "        " "Item3a" 
    "        " "Item3b" 
    "    " "Item4" 
    "        " "Item4a" 
    "        " "Item4b"
    

    statt

    "" "Root" 
    "    " "Item1" 
    "    " "Item2" 
    "    " "Item2" 
    "        " "Item2a" 
    "        " "Item2b" 
    "    " "Item3" 
    "        " "Item3a" 
    "        " "Item3b" 
    "    " "Item4" 
    "        " "Item4a" 
    "        " "Item4b" 
    "    " "Item5" 
    "        " "Item5a" 
    "        " "Item5b"
    

    aber des Rätsels Lösung war das noch nicht ...


  • Mod

    padreigh schrieb:

    Schwere Nuss .. was ich bisher fand:

    Bringt die Datenstruktur auf

    "" "Root" 
    "    " "Item A" 
    "        " "Sub1" 
    "        " "Sub2" 
    "    " "Item2" 
    "        " "Item2a" 
    "        " "Item2b" 
    "    " "Item3" 
    "        " "Item3a" 
    "        " "Item3b" 
    "    " "Item4" 
    "        " "Item4a" 
    "        " "Item4b"
    

    Das wäre ja auch die korrekte.
    Aber warum nichts angezeigt wird, ist mir trotzdem ein Rätsel...



  • Hauptänderungen:
    - DocumentTreeModel::addNode(DocRoot* node) Implementierung
    - DocumentTreeModel::index(..) createIndex(row,1 !!!,pointer)
    - DocumentTreeModel::columnCount() return != count();
    - ne Menge Debugausgaben

    -- documenttreemodel.h --

    #ifndef DOCUMENTTREEMODEL_HPP
    #define DOCUMENTTREEMODEL_HPP
    
    #include <QAbstractItemModel>
    #include <QModelIndex>
    #include <vector>
    #include <QtDebug>
    class DocRoot
    {
        std::vector<DocRoot*> children;
        DocRoot* parent;
        QString text;
    public:
        DocRoot(QString text,DocRoot* parent=0):parent(parent),text(text){}
        virtual ~DocRoot(){for(size_t i =0; i < children.size(); ++i)delete children[i];}
        void addNode(DocRoot* node){children.push_back(node);node->parent = this;}
        void removeNode(DocRoot* node){}
        QString getText()const{return text;}
        DocRoot* getByIndex(int i)
        {
            return i < children.size() && i >= 0 ? children[i] : 0;
        }
        DocRoot* getParent(){return parent;}
        int count()const {return children.size();}
        int row(DocRoot* p)
        {
            for(int i =0;parent && i < children.size(); ++i)
            {
                if(p == children[i])
                    return i;
            }
            return 0;
        }
        int row()
        {
            if(parent)
                return parent->row(this);
            return 0;
        }
        std::vector<DocRoot*> getAllChilds() { return children; }
    };
    
    class DocumentTreeModel : public QAbstractItemModel
    {
    Q_OBJECT
    DocRoot* doc;
    public:
        explicit DocumentTreeModel(QObject *parent = 0);
        virtual ~DocumentTreeModel(){delete doc;}
        QVariant data(const QModelIndex &index, int role) const;
        Qt::ItemFlags flags(const QModelIndex &index) const;
        QVariant headerData(int section, Qt::Orientation orientation,
                     int role = Qt::DisplayRole) const;
        QModelIndex index(int row, int column,
                   const QModelIndex &parent = QModelIndex()) const;
        QModelIndex parent(const QModelIndex &index) const;
        int rowCount(const QModelIndex &parent = QModelIndex()) const;
        int columnCount(const QModelIndex &parent = QModelIndex()) const;
        void update();
        void addNode(DocRoot* node){
            beginInsertRows(QModelIndex(),doc->count(),doc->count()+1);
            doc->addNode(node);
            endInsertRows();
        }
    
    signals:
    
    public slots:
        void debugOut(int lvl=0, DocRoot * dr=0) {
            if (lvl == 0 && dr == 0)
            {
                debugOut(0, doc);
            }
            else {
                qDebug() << QString(lvl*4,' ') << dr->getText();
                foreach(DocRoot *ch, dr->getAllChilds())
                    debugOut(lvl+1, ch);
            }
        }
    };
    
    #endif // DOCUMENTTREEMODEL_HPP
    

    -- documenttreemodel.cpp --

    #include "documenttreemodel.hpp"
    #include <QMessageBox>
    #include <QtDebug>
    
    DocumentTreeModel::DocumentTreeModel(QObject *parent) :
        QAbstractItemModel(parent)
    {
        doc = new DocRoot("Root");
        DocRoot * it1 = new DocRoot("Item A");
        it1->addNode(new DocRoot("Sub1"));
        it1->addNode(new DocRoot("Sub2"));
        doc->addNode(it1);
    
    }
    
    QModelIndex DocumentTreeModel::index(int row, int column, const QModelIndex &parent) const
     {
        DocRoot* p = 0;
        QString msg = "INDEX for ";
    
        if ( !parent.isValid())
        {
            p = doc;
            msg.append("ROOT_ITEM(");
        }
        else
        {
            p = static_cast<DocRoot*>(parent.internalPointer());
            msg.append("     ITEM(");
        }
    
        msg.append(p->getText()+")")
                .append(" get child #"+QString::number(row)+" (");
    
        DocRoot * child = p->getByIndex(row);
    
        if (child)
        {
            msg.append(child->getText()+")");
            qDebug() << msg;
    
            return createIndex(row,1,child);
        }
    
        msg.append("invalid)");
        qDebug() << msg;
    
        return QModelIndex();
    }
    
    QModelIndex DocumentTreeModel::parent(const QModelIndex &index) const
     {
        if (!index.isValid())
        {
            qDebug() << "dtm::PARENT() -> invalid QModelIndex()";
            return QModelIndex();
        }
    
        DocRoot* p = static_cast<DocRoot*>(index.internalPointer());
    
        if (! p || p == doc)
        {
            qDebug() << "dtm::PARENT() -> invalid QModelIndex()";
            return QModelIndex();
        }
    
        DocRoot* par = p->getParent();
    
        if (par == doc )
        {
            qDebug() << "dtm::PARENT() -> invalid QModelIndex()";
            return QModelIndex();
        }
    
        qDebug() << "dtm::PARENT() -> createIndex("
                 << par->row() << ",0," << par->getText() << ")";
    
        return createIndex(par->row(), 0, par);
    
        //
     }
    
    int DocumentTreeModel::rowCount(const QModelIndex &parent) const
    {
        if (!parent.isValid())
        {
            qDebug() << "dtm::ROW_COUNT " << doc->count() << "(" << doc->getText() << ")";
            return doc->count();
        }
        DocRoot* p = static_cast<DocRoot*>(parent.internalPointer());
    
        if (p)
        {
            qDebug() << "dtm::ROW_COUNT " << p->count() << "(" << p->getText() << ")";
    
            return p->count();
        }
        return 0;
     }
    
    int DocumentTreeModel::columnCount(const QModelIndex &parent) const
     {
        if(parent.isValid())
        {
            DocRoot* p = static_cast<DocRoot*>(parent.internalPointer());
            if (p)
                return 1;
            else
                return 0;
        }
        return 1;
     }
    
    QVariant DocumentTreeModel::data(const QModelIndex &index, int role) const
     {
        if (! role == Qt::DisplayRole) return QVariant();
    
        QString msg = "dtm::DATA (" + QString::number(index.row()) + ", "
                      + QString::number(index.column()) + ", ";
    
        if (index.parent().isValid()) msg.append("parent:"
                      + static_cast<DocRoot*>(index.parent().internalPointer())->getText()
                      + ")");
        msg.append("with role: [" + QString::number(role) + "] ");
    
         if (!index.isValid())
         {
             qDebug() << msg << " with invalid index";
             return QVariant();
         }
    
        DocRoot* p = static_cast<DocRoot*>(index.internalPointer());
        if (p)
        {
            qDebug() << msg << " with text " << p->getText();
            return QVariant(p->getText());
        }
    
        qDebug() << msg << " with invalid child";
        return QVariant();
    
     }
    
    Qt::ItemFlags DocumentTreeModel::flags(const QModelIndex &index) const
     {
         if (!index.isValid())
             return 0;
         qDebug() << "flags";
         return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
     }
    
    QVariant DocumentTreeModel::headerData(int section, Qt::Orientation orientation,
                                    int role) const
     {
         return QVariant();
     }
    
    void DocumentTreeModel::update()
    {
        emit dataChanged(createIndex(0,0,doc->getByIndex(0)),createIndex(doc->count()-1,0,doc->getByIndex(doc->count()-1)));
    }
    

    -- mainwindow.cpp --

    #include "mainwindow.hpp"
    #include "ui_mainwindow.h"
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
        model = new DocumentTreeModel();
        ui->treeView->setModel(model);
    
        qDebug() << "<Startup>";
            model->debugOut();
        qDebug() << "<Startup />";
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
        delete model;
    }
    
    void MainWindow::changeEvent(QEvent *e)
    {
        QMainWindow::changeEvent(e);
        switch (e->type()) {
        case QEvent::LanguageChange:
            ui->retranslateUi(this);
            break;
        default:
            break;
        }
    }
    
    void MainWindow::on_pushButton_clicked()
    {
        static int num = 1;
        QString txt("ButtonADD_" + QString::number(++num));
        DocRoot* root = new DocRoot(QString(txt+"_Item"));
        root->addNode(new DocRoot(QString(txt+"_sub_a")));
        root->addNode(new DocRoot(QString(txt+"_sub_b")));
    
        model->addNode(root);
        model->update();
        model->debugOut();
    }
    

  • Mod

    Ja, jetzt klappts. Danke 😃

    Allerdings ist dass hier falsch:

    return createIndex(row,1,child);
    

    So kann er nämlich nicht in die Verästelung des Baumes rein.

    Ein letztes Problem habe ich allerdings:

    Das letzte Item im Baum wird nicht korrekt dargestellt, da wird die Linie weitergezogen als es sein sollte.
    So, als wäre darunter noch ein Knoten...



  • Ich seh leider keine Linie (anderer Windowmanager 😉 ) viel Glück beim weitersuchen


  • Mod

    Hab gerade mal kurz deinen Code durch C&P komplett bei mir eingefügt, bleibt aber das ergebnis, das die letzte Node, wenn ausgeklappt falsch gezeichnet wird unter WinDoof... 😕


Anmelden zum Antworten