Qt: Browsing filesystem with QListView and QFileSystemModel. How to higlight first item in a folder?
Solution 1
I think I have it working now. After changing the rootIndex of the list, I have to wait for the model to do its work. I don't set the currentIndex in the new directory until I get the directoryLoaded signal from the model. Now highlighting works. The data from the model is not sorted, so row=0 & col=0 is not the first item in the list after all, but that's another topic :)
Edit: fiddled a bit more with this tonight, and added the final touches.
const QString rp = "/home/anders/src";
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
model = new QFileSystemModel;
model->setRootPath(rp);
list = new QListView;
list->setModel(model);
list->show();
connect(model,
SIGNAL(directoryLoaded(QString)),
this,
SLOT(model_directoryLoaded(QString)));
QTimer::singleShot(2000, this, SLOT(changeRoot()));
}
void MainWindow::model_directoryLoaded(QString path)
{
qDebug() << "loaded" << path;
model->sort(0, Qt::AscendingOrder);
list->setCurrentIndex(model->index(0, 0, list->rootIndex()));
}
void MainWindow::changeRoot()
{
qDebug() << "changeRoot";
model->setRootPath(rp + "/trunk");
list->setRootIndex(model->index(rp + "/trunk"));
}
MainWindow::~MainWindow()
{
delete list;
delete model;
delete ui;
}
Solution 2
I had some help from here and these are my conclusions:
In order for the QFileSystemModel to work properly, the GUI event loop needs to be running. I'm guessing you added the QTimer::singleShot(...)
line because of this? However, you only gave it 2 seconds. From the documentation for QFileSystemModel:
Calls to rowCount() will return 0 until the model populates a directory.
This means after your MainWindow is constructed, you have 2 seconds for everything else to be constructed, the GUI event loop to start, and then for the QFileSystemModel to populate the directory. Are the directories where this is failing large? I am guessing so.
What you could try would be to give the timer a longer interval. A better solution may be to create a shortcut that selects the first thing in the list, like this:
QShortcut* sh = new QShortcut(QKeySequence("Ctrl+1"), this);
connect(sh, SIGNAL(activated()), this, SLOT(LightUpFirst()));
and the LightUpFirst function does the selecting. Hope that helps!
anr78
Updated on June 21, 2022Comments
-
anr78 about 2 years
I'm doing what the topic says on a system without keyboard/mouse, so I need to make this work "from code". When I change the RootIndex of the QListView I want to highlight the first row.
Here's mainwindow.cpp from a small testproject I've made:
#include "mainwindow.h" #include "ui_mainwindow.h" #include <QEvent> #include <QKeyEvent> #include <QDebug> #include <QTimer> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); model = new QFileSystemModel; model->setRootPath("/Users/anders/Downloads/Browser"); listView = new QListView; listView->setModel(model); listView->show(); QTimer::singleShot(2000, this, SLOT(LightItUp1())); } void MainWindow::LightItUp1() { qDebug("LightItUp1"); listView->setRootIndex(model->index("/Users/anders/Downloads")); listView->setCurrentIndex(model->index(0, 0, listView->rootIndex())); QTimer::singleShot(2000, this, SLOT(LightItUp2())); } void MainWindow::LightItUp2() { qDebug("LightItUp2"); listView->setRootIndex(model->index("/Users/anders/Downloads/Browser")); listView->setCurrentIndex(model->index(0, 0, listView->rootIndex())); QTimer::singleShot(2000, this, SLOT(LightItUp3())); } void MainWindow::LightItUp3() { qDebug("LightItUp3"); listView->setRootIndex(model->index("/Users/anders/Downloads")); listView->setCurrentIndex(model->index(0, 0, listView->rootIndex())); QTimer::singleShot(2000, this, SLOT(LightItUp4())); } void MainWindow::LightItUp4() { QString p = "/Users/anders/Downloads/Mail"; listView->setRootIndex(model->index(p)); listView->setCurrentIndex(model->index(0, 0, listView->rootIndex())); } MainWindow::~MainWindow() { delete listView; delete model; delete ui; }
In this example LightItUp 1-3 do what I want, but LightItUp4 does not. If I swap the folders in 2 & 4 both of them fail to do what I want, while 1 & 3 still work. I suspect I have misunderstood something about how to use this Model/View, but have no idea what.
Edit: created a simpler example with the error checking @buck mentioned. See the comments in the source code.
const QString rp = "/home/anders/src/"; MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); model = new QFileSystemModel; model->setRootPath(rp); //using model->setRootPath(rp + "/trunk") instead works listView = new QListView; listView->setModel(model); listView->show(); QTimer::singleShot(2000, this, SLOT(LightItUp1())); } void MainWindow::LightItUp1() { qDebug("LightItUp1"); QModelIndex p = model->index(rp + "/trunk"); if (!p.isValid()) { qDebug("index not valid\n"); return; } //model->setRootPath(rp + "/trunk") here does not make it work listView->setRootIndex(p); listView->setCurrentIndex(model->index(0, 0, p)); }
I thought that when I do setRootPath(rp) on the model, and then set the view to use the model, the view should able to move around in all subfolders of rp if I set the indexes correctly. I'll reread the Qtdocs on Model/View, QListView and QFileSystemModel, but wanted to post this in case someone understands what is happening.
-
anr78 almost 13 yearsI've read that post as well, and it is indeed the reason for the timer. Actually the directories are not very large, and even if I increase it to 20 seconds it fails.
-
anr78 almost 13 yearsIn my real code the time from the model starts to populate until I try the operate on the listView can be several minutes, but it still fails in the same way.
-
buck almost 13 yearsWhat are the contents of the directory where this is failing? Is it all directories or all files or mixed (maybe this plays a role??)? Also, it could be that the directory where this is failing is not loaded by the QFileSystemModel. Maybe when you change the root index of the view you should also call setRootPath
-
anr78 almost 13 yearsThe contents of the dir does not seem to matter. I tried setting rootPath (see the comment in my example) without any luck, but I suspect I should wait for some signals from QFileSystemModel before acting. When I wait for directoryLoaded(QString) I manage to highlight something, thought it's not the first directory. But hey, its progress.
-
ransh over 9 yearsHi, Did you manage to highlight specific file ? Is the code posted here the final results ? How do you scroll down and up between files (and highlight each time the selected file) Thanks, Ran
-
anr78 over 9 yearsI do not remember how this ended. It was a long time ago, and the code does not exist anymore (and never reached a VCS). Sorry.
-
ransh over 9 yearsThanks, so you do not recommend to use this code, I understand, Right ?
-
anr78 over 9 yearsIf it works it's usable. I honestly don't remember :)