qttreeviewqtreeviewqtreewidgetqtreewidgetitem

Make tree folder from QTreeView or QTreeWidget


read folder tree from a Rest API, then show them to user

Example json response after call API:

[
{"name":"/folder1/file1.txt";"size":"1KB"},
{"name":"/folder1/file2.txt";"size":"1KB"},
{"name":"/folder1/sub/file3.txt";"size":"1KB"},
{"name":"/folder2/file4.txt";"size":"1KB"},
{"name":"/folder2/file5.txt";"size":"1KB"}
]

I only want to make GUI like below image: enter image description here

There are 2 options:

  1. QTreeView

  2. QTreeWidget

In this photo, I used QTreeWidget (with static data). Currently, I don't know make data model for this.

I made TreeModel to set data for QtreeView. But When them shown in GUI, All of the data only show in column Name. I copied the code from http://doc.qt.io/qt-5/qtwidgets-itemviews-simpletreemodel-example.html

But now I can't resolve this problem. I need an example source code for this. Plus, I also only want show a tree view simply.

don't use QFileSystem because data get from Rest API.


Solution

  • What you have to do is parsing the json by getting the name of the file and the size, then you separate the name using the "/", and add it to the model in an appropriate way.

    #include <QApplication>
    #include <QJsonDocument>
    #include <QJsonArray>
    #include <QJsonObject>
    #include <QStandardItemModel>
    #include <QTreeView>
    #include <QFileIconProvider>
    
    QStandardItem * findChilItem(QStandardItem *it, const QString & text){
        if(!it->hasChildren())
            return nullptr;
        for(int i=0; i< it->rowCount(); i++){
            if(it->child(i)->text() == text)
                return it->child(i);
        }
        return nullptr;
    }
    
    static void appendToModel(QStandardItemModel *model, const QStringList & list, const QString & size){
        QStandardItem *parent = model->invisibleRootItem();
        QFileIconProvider provider;
    
        for(QStringList::const_iterator it = list.begin(); it != list.end(); ++it)
        {
            QStandardItem *item = findChilItem(parent, *it);
            if(item){
                parent = item;
                continue;
            }
            item = new QStandardItem(*it);
            if(std::next(it) == list.end()){
                item->setIcon(provider.icon(QFileIconProvider::File));
                parent->appendRow({item, new QStandardItem(size)});
            }
            else{
                item->setIcon(provider.icon(QFileIconProvider::Folder));
                parent->appendRow(item);
            }
            parent = item;
        }
    }
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        QStandardItemModel model;
        model.setHorizontalHeaderLabels({"Name", "Size"});
        const std::string json = R"([
                                 {"name":"/folder1/file1.txt";"size":"1KB"},
                                 {"name":"/folder1/file2.txt";"size":"1KB"},
                                 {"name":"/folder1/sub/file3.txt";"size":"1KB"},
                                 {"name":"/folder2/file4.txt";"size":"1KB"},
                                 {"name":"/folder2/file5.txt";"size":"1KB"}
                                 ])";
    
        QJsonParseError parse;
        // The string is not a valid json, the separator must be a comma
        // and not a semicolon, which is why it is being replaced
        QByteArray data = QByteArray::fromStdString(json).replace(";", ",");
        QJsonDocument const& jdoc =  QJsonDocument::fromJson(data, &parse);
        Q_ASSERT(parse.error == QJsonParseError::NoError);
        if(jdoc.isArray()){
            for(const QJsonValue &element : jdoc.array() ){
                QJsonObject obj = element.toObject();
                QString name = obj["name"].toString();
                QString size = obj["size"].toString();
                appendToModel(&model, name.split("/", QString::SkipEmptyParts), size);
            }
        }
    
        QTreeView view;
        view.setModel(&model);
        view.show();
        return a.exec();
    }
    

    Note: the semicolon is not a valid separator for the json, so I had to change it.

    enter image description here