0

I'm trying to create a small app, which will find, read and export some *.xml documents. App must read the hierarchical folder structure and visualise it in QTreeView on the form. For better managing I want it to expand all objects of treeview on the app's startup. I've tried many different solutions like this:

void expandChildren(const QModelIndex &index, QTreeView *view)
    {
        if (!index.isValid())
        {
            return;
        }
        int childCount = index.model()->rowCount(index);
        for (int i = 0; i < childCount; i++)
        {
            const QModelIndex &child = index.child(i, 0);
            expandChildren(child, view);
        }
        if (!view->isExpanded(index))
        {
            view->expand(index);
        }
    }

from some forums and embeded solutions like QTreeView::expandRecursively and QTreeView::expandAll, but I haven't achived what I wanted.

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QFileSystemModel>
#include <QDebug>
#include <QDirModel>
#include <QTreeView>


QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

    QModelIndex fs_index;
    QModelIndex child_1_index;
    QModelIndex child_2_index;
    QModelIndex child_3_index;
    QFileSystemModel *fs_model = new QFileSystemModel;

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void on_treeView_clicked(const QModelIndex &index);

    void on_pushButton_2_clicked();

    void on_pushButton_clicked();

private:
    Ui::MainWindow *ui;

    void expandChildren(const QModelIndex &index, QTreeView *view)
    {
        if (!index.isValid())
        {
            return;
        }
        int childCount = index.model()->rowCount(index);
        for (int i = 0; i < childCount; i++)
        {
            const QModelIndex &child = index.child(i, 0);
            expandChildren(child, view);
        }
        if (!view->isExpanded(index))
        {
            view->expand(index);
        }
    }

};
#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
QString str_root_path;
QDir dir;

qDebug() << "Current user's home folder is: " <<QDir::home().path();
str_root_path = QDir::home().path() + "/AppData/Local/app/settings";
qDebug() << "Settings storing folder id: " << str_root_path;
dir.setPath(str_root_path);
if (!dir.exists())
{
    qDebug() << "Settings folder doesn't exist.";
    return;
}

if (!dir.isReadable())
{
    qDebug() << "Folder found. Read access denied. Check access rights.";
    return;
}

qDebug() << "Folder found. Read access granted. Reading...";

ui->treeView->setModel(fs_model);

fs_index = fs_model->index(str_root_path);
qDebug() << fs_model->fileName(fs_index);

fs_model->setRootPath(str_root_path);
QStringList filter;
filter << "*.xml";
fs_model->setNameFilters(filter);
fs_model->setFilter( QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot);


ui->treeView->setRootIndex(fs_index);
ui->treeView->setCurrentIndex(fs_index);

for (int i = 1; i < fs_model->columnCount(); i++)
{
    ui->treeView->setColumnHidden(i, true);
}

ui->treeView->show();

qDebug().nospace() << "View loaded. Expanding....";

ui->treeView->setExpanded(fs_index, true);
int fs_index_rows = fs_model->rowCount(fs_index);
qDebug().nospace() << "Number of found profiles:" << fs_index_rows;
for (int i = 0; i < fs_index_rows; ++i)
{
    child_1_index = fs_model->index(i,0,fs_index);
    ui->treeView->setExpanded(child_1_index, true);
    int child_1_index_rows = fs_model->rowCount(child_1_index);

    qDebug().nospace() << "Step #" << i+1 << " Object name: " << fs_model->fileName(child_1_index) << ". Num of children: " << child_1_index_rows;

    for (int j = 0; j < child_1_index_rows; ++j)
    {
        child_2_index = ui->treeView->model()->index(j,0,child_1_index);
        //qDebug() << child_2_index;
        ui->treeView->setExpanded(child_2_index, true);
        int child_2_index_rows = ui->treeView->model()->rowCount(child_2_index);
        qDebug().nospace() << "Step #" << i+1 << "/" << j+1 << " Object name: " << fs_model->fileName(child_1_index) << "/" << fs_model->fileName(child_2_index) << ". Num of children: " << child_2_index_rows;

        for (int k = 0; k < child_2_index_rows; ++k)
        {
            child_3_index = ui->treeView->model()->index(k,0,child_2_index);
            ui->treeView->setExpanded(child_3_index, true);
            int child_3_index_rows = ui->treeView->model()->rowCount(child_3_index);
            qDebug().nospace() << "Step #" << i+1 << "/" << j+1 << "/" << k+1 << " Object name: " << fs_model->fileName(child_1_index) << "/" << fs_model->fileName(child_2_index) << "/" << fs_model->fileName(child_3_index) << ". Num of children: " << child_3_index_rows;
        }

        }
    }

}

If I paste that code to the slot which connected to the signal of "pushbutton_Clicked" for example, each click expand the treeview for a one more depth level (the same action appearing if I connect QTreeView::expandRecursively or QTreeView::expandAll to "pushbutton_Clicked"). I've tried to debug every step of app and I understuud that each new index object can't achive parent's index of filesystemmodel.

Please help me understand, where is the error and how to fix it.

I'm new in programming on Qt and my knoledgement is not full but I still searching, reading and trying to understand.

Thank you in advance and sorry for bad English.

All the code of app:

main.cpp

#include "mainwindow.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QFileSystemModel>
#include <QDebug>
#include <QDirModel>
#include <QTreeView>


QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

    QModelIndex fs_index;
    QFileSystemModel fs_model;

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void on_treeView_clicked(const QModelIndex &index);

    void on_pushButton_2_clicked();

    void on_pushButton_clicked();

private:
    Ui::MainWindow *ui;

    void expandChildren(const QModelIndex &index, QTreeView *view)
    {
        if (!index.isValid()) {
            return;
        }

        int childCount = index.model()->rowCount(index);
        for (int i = 0; i < childCount; i++) {
            const QModelIndex &child = index.child(i, 0);
            // Recursively call the function for each child node.
            expandChildren(child, view);
        }

        if (!view->isExpanded(index))
        {
            view->expand(index);
        }
    }

    void expand_the_tree(const QModelIndex &root_index, QTreeView *view)
    {

        qDebug() << fs_model.canFetchMore(root_index);

        while (fs_model.canFetchMore(root_index) == true)
        {
            fs_model.fetchMore(root_index);
        }

        qDebug().nospace() << "Model fetched on root layer.";

        QModelIndex child_1_index;
        QModelIndex child_2_index;
        QModelIndex child_3_index;

        view->expand(root_index);


        int root_index_rows = fs_model.rowCount(root_index);
        qDebug().nospace() << "Number of found profiles:" << root_index_rows;

        for (int i = 0; i < root_index_rows; ++i)
        {
            child_1_index = fs_model.index(i,0,root_index);
            view->expand(child_1_index);
            expandChildren(child_1_index, view);
            int child_1_index_rows = fs_model.rowCount(child_1_index);

            qDebug().nospace() << "Step #" << i+1 << " Object name: " << fs_model.fileName(child_1_index) << ". Num of children: " << child_1_index_rows;

            for (int j = 0; j < child_1_index_rows; ++j)
            {
                child_2_index = fs_model.index(j,0,child_1_index);
                //qDebug() << child_2_index;
                view->expand(child_2_index);
                int child_2_index_rows = fs_model.rowCount(child_2_index);
                qDebug().nospace() << "Step #" << i+1 << "/" << j+1 << " Object name: " << fs_model.fileName(child_1_index) << "/" << fs_model.fileName(child_2_index) << ". Num of children: " << child_2_index_rows;

                for (int k = 0; k < child_2_index_rows; ++k)
                {
                    child_3_index = fs_model.index(k,0,child_2_index);
                    view->expand(child_3_index);
                    int child_3_index_rows = fs_model.rowCount(child_3_index);
                    qDebug().nospace() << "Step #" << i+1 << "/" << j+1 << "/" << k+1 << " Object name: " << fs_model.fileName(child_1_index) << "/" << fs_model.fileName(child_2_index) << "/" << fs_model.fileName(child_3_index) << ". Num of children: " << child_3_index_rows;
                }

            }
        }
    }

};
#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QApplication>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    QString str_root_path;
    QDir dir;


    qDebug() << "Current user's home folder is: " <<QDir::home().path();
    str_root_path = QDir::home().path() + "/AppData/Local/app/settings";
    qDebug() << "Preset's storing folder id: " << str_root_path;
    dir.setPath(str_root_path);
    if (!dir.exists())
    {
        qDebug() << "Settings folder doesn't exist.";
        return;
    }

    if (!dir.isReadable())
    {
        qDebug() << "Folder found. Read access denied. Check access rights.";
        return;
    }

    qDebug() << "Folder found. Read access granted. Reading...";



    fs_index = fs_model.index(str_root_path);
    qDebug() << fs_model.fileName(fs_index);

    fs_model.setRootPath(str_root_path);

    QStringList filter;
    filter << "*.xml";
    fs_model.setNameFilters(filter);
    fs_model.setFilter( QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot);

    ui->treeView->setModel(&fs_model);
    ui->treeView->setRootIndex(fs_index);
    ui->treeView->setCurrentIndex(fs_index);

    qDebug() << fs_model.canFetchMore(fs_index);

    for (int c = 1; c < fs_model.columnCount(); c++)
    {
        ui->treeView->setColumnHidden(c, true);
    }

    qDebug().nospace() << "View loaded. Expanding....";

    expand_the_tree(fs_index, ui->treeView);

}

MainWindow::~MainWindow()
{
    delete ui;
}


void MainWindow::on_treeView_clicked(const QModelIndex &index)
{
    qDebug() << index;
}

void MainWindow::on_pushButton_2_clicked()
{
    expandChildren(fs_index, ui->treeView);
}

void MainWindow::on_pushButton_clicked()
{
        expand_the_tree(fs_index, ui->treeView);
}

mainwindow.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>712</width>
    <height>635</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <widget class="QTreeView" name="treeView">
    <property name="geometry">
     <rect>
      <x>20</x>
      <y>60</y>
      <width>311</width>
      <height>531</height>
     </rect>
    </property>
   </widget>
   <widget class="QTableView" name="tableView">
    <property name="geometry">
     <rect>
      <x>370</x>
      <y>60</y>
      <width>321</width>
      <height>531</height>
     </rect>
    </property>
   </widget>
   <widget class="QPushButton" name="pushButton">
    <property name="geometry">
     <rect>
      <x>20</x>
      <y>600</y>
      <width>75</width>
      <height>23</height>
     </rect>
    </property>
    <property name="text">
     <string>Refresh</string>
    </property>
   </widget>
   <widget class="QPushButton" name="pushButton_2">
    <property name="geometry">
     <rect>
      <x>110</x>
      <y>600</y>
      <width>75</width>
      <height>23</height>
     </rect>
    </property>
    <property name="text">
     <string>Retrieve all</string>
    </property>
   </widget>
  </widget>
 </widget>
 <resources/>
 <connections/>
</ui>
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459

1 Answers1

0

Is this the whole code? Can you provide also the main?

Anyway I am not able to compile your code, line 29:

ui->treeView->setModel(fs_model);

calls the function treeView, that does not exist.

Anyway if you wanna do a UI I suggest you use QML and you could have a look at the already done example in qt.

Tree model https://doc-snapshots.qt.io/qt5-5.11/qtquickcontrols-filesystembrowser-example.html

You can look and run them when you open Qt creator. you click on welcome, then example and in the end, you type tree

Once you have the basic code you can modify it as you want.

Marco Medri
  • 176
  • 3
  • QTreeView does have the setModel method since it inherits from QAbstractItemView: https://doc.qt.io/qt-5/qtreeview-members.html – eyllanesc Apr 05 '20 at 14:04
  • No, it's ui that does not have a method treeView. Anyway, if you have other code to post, put it here, so I can try it :) – Marco Medri Apr 05 '20 at 14:40
  • mmm, it seems that you have not used Qt Designer(MOC), clearly the OP has added a QTreeView whose name is treeView that is accessed through ui: `ui->treeView` – eyllanesc Apr 05 '20 at 14:43
  • 1. I've read about tree model. 2. Yes, "treeView" is QTreeView object on the form and it is accessed through UI. 3. The problem is in empy response from "rowCount" of model's child index. Google gave nothing... – Olgerd Kiselmann Apr 05 '20 at 17:47
  • I've add the whole code. .canFetchMode returns false, but .rowCount continue to return zero of rows when directory is not empty and objects appears in treeView... – Olgerd Kiselmann Apr 05 '20 at 17:56
  • I tried also the function [slot]void QTreeView::expandRecursively(const QModelIndex &index, int depth = -1) but nothing, it doesn't work. it seems like the model doesn't have the child associated with it. – Marco Medri Apr 05 '20 at 18:04
  • According to the documentation: Unlike QDirModel, QFileSystemModel uses a separate thread to populate itself so it will not cause the main thread to hang as the file system is being queried. Calls to rowCount() will return 0 until the model populates a directory. – Marco Medri Apr 05 '20 at 18:08