How to capture parent directory from lambda - c++

In my code I list subdirectories name(only child dir) and if i click this subdirectory , the images inside this subdir will be displayed. In my case I cant capture parent directory from inside lambda. How can I do that?
Dir directory = QFileDialog::getExistingDirectory(this, tr("Open Directory"),"/home",
QFileDialog::ShowDirsOnly| QFileDialog::DontResolveSymlinks);
for (const QFileInfo &finfo: directory.entryInfoList()) {
QDir dir(finfo.absoluteFilePath());
ui->listWidget_dirs->addItem(dir.dirName());
}
//QStringList files = directory.entryList(QDir::Dirs);
//ui->listWidget_dirs->addItems(files);
auto listWidget_images = new QListWidget();//set listwidget to display images
listWidget_images->setMinimumSize(1200,400);
listWidget_images->setViewMode(QListWidget::IconMode);
listWidget_images->setIconSize(QSize(320,240));
listWidget_images->setResizeMode(QListWidget::Adjust);
connect(ui->listWidget_dirs, & QListWidget::itemClicked,[listWidget_images,this](QListWidgetItem *item)
{
listWidget_images->show();
listWidget_images->clear();
/*this is where it is wrong*/ QDir path(directory + '/' + item->text());
path.setNameFilters({"*.png", "*.jpg"});
for(const QFileInfo & finfo: path.entryInfoList()){
QListWidgetItem *item = new QListWidgetItem(QIcon(finfo.absoluteFilePath()), finfo.fileName());
listWidget_images->addItem(item);
}
});

I just wanted to leave a note. Be sure that your objects alive during your lamda exist, especially listWidget_images. If you delete it elsewhere, your lamda will crash. I would recommment to change the connect line a little:
from
connect(ui->listWidget_dirs, & QListWidget::itemClicked,[directory,listWidget_images, this](QListWidgetItem *item)
to
connect(ui->listWidget_dirs, & QListWidget::itemClicked, listWidget_images, [directory,listWidget_images, this](QListWidgetItem *item)
If you put the pointer listWidget_images before the capture list [] the lamda will be destroyed, when the object from listWidget_images is destroyed. Otherwise your application will crash in the first line of your lamda if the object doesn't exist anymore.

Well I get how to do it, this is the code.
QDir directory = QFileDialog::getExistingDirectory(this, tr("Open Directory"),"/home",
QFileDialog::ShowDirsOnly| QFileDialog::DontResolveSymlinks);
for (const QFileInfo &finfo: directory.entryInfoList()) {
QDir dir(finfo.absoluteFilePath());
ui->listWidget_dirs->addItem(dir.dirName());
}
auto listWidget_images = new QListWidget();//set listwidget to display images
listWidget_images->setMinimumSize(1200,400);
listWidget_images->setViewMode(QListWidget::IconMode);
listWidget_images->setIconSize(QSize(320,240));
listWidget_images->setResizeMode(QListWidget::Adjust);
connect(ui->listWidget_dirs, & QListWidget::itemClicked,[directory,listWidget_images, this](QListWidgetItem *item)
{
listWidget_images->show();
listWidget_images->clear();
// QDir path(item->text());
QDir dir = directory.absolutePath() + '/' + item->text();
dir.setNameFilters({"*.png", "*.jpg"});
for(const QFileInfo & finfo: dir.entryInfoList()){
QListWidgetItem *item = new QListWidgetItem(QIcon(finfo.absoluteFilePath()), finfo.fileName());
listWidget_images->addItem(item);
}
});

Related

How to filter image files from selected directory (which is inside listWidget)

I have a problem that I don't know how to filter images from a selected directory. I usually use directory.setNameFilters({"*.png", "*.jpg"}); but in this case I can't use that because I need to use the selected directory inside a listWidget. I use signal and slot functions. I mean if I click a directory which is inside a listWidget, the images inside this directory will be displayed in another listWidget. If I click another directory it will do the same function. Please take a look my code.
QDir directory = QFileDialog::getExistingDirectory(this, tr("Open Directory"),"/home", QFileDialog::ShowDirsOnly| QFileDialog::DontResolveSymlinks);
auto listWidget_images = new QListWidget();//set listwidget to display images
listWidget_images->setMinimumSize(1200,400);
listWidget_images->setViewMode(QListWidget::IconMode);
listWidget_images->setIconSize(QSize(320,240));
listWidget_images->setResizeMode(QListWidget::Adjust);
for(const QFileInfo & finfo: directory.entryInfoList()){
ui->listWidget_dirs->addItem(finfo.absoluteFilePath());
}
connect(ui->listWidget_dirs, & QListWidget::itemClicked,[listWidget_images,this](QListWidgetItem *item)
{
listWidget_images->show();
directory.setNameFilters({"*.png", "*.jpg"});
for(const QFileInfo & finfo: directory.entryInfoList()){
QListWidgetItem *item = new QListWidgetItem(QIcon(finfo.absoluteFilePath()), finfo.fileName());
listWidget_images->addItem(item);
}
});
you have to create the QDir using the text of the QListWidgetItem.
On the other hand the method to use to obtain the list of subdirectories gets file and directories without distinguishing one from another, I have fixed that part.
QString directory = QFileDialog::getExistingDirectory(this,
tr("Open Directory"),
QDir::homePath(),
QFileDialog::ShowDirsOnly| QFileDialog::DontResolveSymlinks);
auto listWidget_images = new QListWidget();//set listwidget to display images
listWidget_images->setMinimumSize(1200,400);
listWidget_images->setViewMode(QListWidget::IconMode);
listWidget_images->setIconSize(QSize(320,240));
listWidget_images->setResizeMode(QListWidget::Adjust);
QDirIterator diter(directory, QDir::Dirs | QDir::NoDotAndDotDot);
while (diter.hasNext()) {
ui->listWidget_dirs->addItem(diter.next());
}
connect(ui->listWidget_dirs, &QListWidget::itemClicked,[listWidget_images](QListWidgetItem *item)
{
listWidget_images->show();
listWidget_images->clear();
QDir directory(item->text());
directory.setNameFilters({"*.png", "*.jpg"});
for(const QFileInfo & finfo: directory.entryInfoList()){
QListWidgetItem *item = new QListWidgetItem(QIcon(finfo.absoluteFilePath()), finfo.fileName());
listWidget_images->addItem(item);
}
});

Getting full path from QListWidget

I have 2 listwidgets, lets call them listwidgetinput and listwidgetoutput. I have alot of files(only file name) on listwidgetinput. And i trim the file name before adding it to listwidgetinput like this it.fileName(). and i transfer the selected files to listdigetoutput like:
QList <QListWidgetItem*> items=ui->listWidgetinput->selectedItems();
for(int j=0;j<items.count();j++)
{
list= items.at(j)->text();
ui->listWidgetOutput->insertItem(j,list);
After i transfer the file can i get the path for all the files?. If Yes, how?
edit: code where whole path is available.
QString Dir, Type;
QStringList Files;
Qlistwidget wid
if (index==0)
{
Dir.append(C:\desktop....);
type.append(".txt")
wid = ui->listwidgetinput_txt;
}
if (index ==1)
{
Dir.append(C:\desktop....);
type.append(".doc")
wid = ui->listwidgetinput_doc
}
QDirIterator it(Dir, QStringList() << Type, QDir::Files, QDirIterator::Subdirectories);
while (it.hasNext())
{
it.next();
Files.append(it.fileName());
}
wid->additems(Files);
Use QListWidgetItem::setData() to pass additional "invisible" properties like the full path when creating the item:
auto item = new QListWidgetItem;
item->setText(fileInfo.fileName());
item->setData(Qt::UserRole, fileInfo.absoluteFilePath());
...
Later you can retrieve it via QListWidgetItem::data():
const auto fullPath = item->data(Qt::UserRole).toString();

Iterating through files in folder is very slow in qt

I am iterating through all files in a folder (recursively though all its sub folders) but this is extremely slow..it almost never returns. I could put this in a thread but even than it will not be practical with this speed. Here is my function
int MainWindow::searchXmlFiles(QString rootDir)
{
xmlFileModel->clear(); // xmlFileModel is QStanardItemModel
int count = 0;
XmlFile xmlFile;
QString xmlFilePath;
QDirIterator iter( rootDir, QStringList() << "*.xml", QDir::Files | QDir::NoDotAndDotDot, QDirIterator::Subdirectories);
QDir dir( ui->lineEditSourceFolder->text() );
while(iter.hasNext() )
{
qDebug() << iter.next();
xmlFilePath = iter.filePath();
xmlCollection = xmlFile.openXmlFile( xmlFilePath );
QStandardItem * item = new QStandardItem( QIcon(":/icons/xmlfile.ico") , dir.relativeFilePath( xmlFilePath) );
xmlFileModel->appendRow( item );
count++;
}
QString fileCount = QString("Total of %1 file(s) will be converted from `%2` folder").arg( QString::number(count), rootDir);
ui->labelXmlFileCount->setText( fileCount );
return count;
}
Is this slow speed really expected? Is there way to do the same thing faster?
Update
After comment by Jeremey, if I comment all the work inside the loop (xmlFile.openXmlFile() and QStandardItem creation), it gets quite fast, takes like 3 seconds. If I leave QStandardItem creation there, it takes about 7 seconds/
You can use QDir::entryList() to get full list of XML files at once and then iterate through QStringList of file names.

Where are my QTreeWidgetIcons?

I have a QTreeWidget with QTreeWidgetItem items, however only the root node is showing its icon:
I've been scratching my head on what could turn it off, any hints?
ui->folderTree1->setUpdatesEnabled( false );
QTreeWidgetItem* treeRoot1 = new QTreeWidgetItem(ui->folderTree1);
treeRoot1->setIcon(0, QIcon(":/icons/black.png"));
treeRoot1->setText(0, tr("Root"));
treeRoot1->setExpanded(true);
addFoldersToTreeView(treeRoot1, ui->filePath1->text(), ui->filePath2->text());
ui->folderTree1->setUpdatesEnabled( true );
}
void MainWindow::addFoldersToTreeView(QTreeWidgetItem* currentWidget, QString leftPath, QString rightPath)
{
qDebug() << "MainWindow::addFoldersToTreeView" << leftPath;
QDir dir(leftPath);
QDir dir2(rightPath);
/* Add the folders */
foreach (QString subDir, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot))
{
QString sImageName = ":/icons/black.png";
QTreeWidgetItem* newItem = new QTreeWidgetItem(currentWidget);
qDebug() << "MainWindow::addFoldersToTreeView.sImageName" << sImageName;
newItem->setIcon(0, QIcon(sImageName));
newItem->setText(0, subDir);
newItem->setExpanded(true);
newItem->setData(0, 1, QVariant(leftPath + QDir::separator() + subDir));
/* Recursively add sub-folders */
addFoldersToTreeView(newItem, leftPath + QDir::separator() + subDir, rightPath + QDir::separator() + subDir);
}
The problem is the line:
newItem->setData(0, 1, QVariant(leftPath + QDir::separator() + subDir));
The second argument is the item data role, which you specify to 1 (Qt::DecorationRole). The Qt::DecorationRole should be used for data that is rendered as a decoration in the form of an icon, i.e., this line will cause the the icon you specified before to be replaced with a QVariant object.
Remove that line or change the item data role to something else.

Delete all files in a directory

I need to delete all files in a directory using Qt.
All of the files in the directory will have the extension ".txt".
I don't want to delete the directory itself.
Does anyone know how I can do this? I've looked at QDir but am having no luck.
Bjorns Answer tweeked to not loop forever
QString path = "whatever";
QDir dir(path);
dir.setNameFilters(QStringList() << "*.*");
dir.setFilter(QDir::Files);
foreach(QString dirFile, dir.entryList())
{
dir.remove(dirFile);
}
Ignoring the txt extension filtering... Here's a way to delete everything in the folder, including non-empty sub directories:
In QT5, you can use removeRecursively() on dirs. Unfortunately, that removes the whole directory - rather than just emptying it. Here is basic a function to just clear a directory's contents.
void clearDir( const QString path )
{
QDir dir( path );
dir.setFilter( QDir::NoDotAndDotDot | QDir::Files );
foreach( QString dirItem, dir.entryList() )
dir.remove( dirItem );
dir.setFilter( QDir::NoDotAndDotDot | QDir::Dirs );
foreach( QString dirItem, dir.entryList() )
{
QDir subDir( dir.absoluteFilePath( dirItem ) );
subDir.removeRecursively();
}
}
Alternatively, you could use removeRecursively() on the directory you want to clear (which would remove it altogether). Then, recreate it with the same name after that... The effect would be the same, but with fewer lines of code. This more verbose function, however, provides more potential for detailed exception handling to be added if desired, e.g. detecting access violations on specific files / folders...
Call QDir::entryList(QDir::Files) to get a list of all the files in the directory, and then for each fileName that ends in ".txt" call QDir::remove(fileName) to delete the file.
You started in a good way, look at entryList and of course pass the namefilter you want.
To improve on #user3191791's answer (which removes all files and directories), this answer:
Modernises the code with a range-based for loop
Provides optional error checking
The code:
struct FileOperationResult
{
bool success;
QString errorMessage;
};
FileOperationResult removeDirContents(const QString &dirPath)
{
QDir dir(dirPath);
dir.setFilter(QDir::NoDotAndDotDot | QDir::Files);
const QStringList files = dir.entryList();
for (const QString &fileName : files) {
if (!dir.remove(fileName)) {
const QString failureMessage = QString::fromUtf8(
"Failed to remove file %1 from %2").arg(fileName, dirPath);
return { false, failureMessage };
}
}
dir.setFilter(QDir::NoDotAndDotDot | QDir::Dirs);
const QStringList dirs = dir.entryList();
for (const QString &dirName : dirs) {
QDir subDir(dir.absoluteFilePath(dirName));
if (!subDir.removeRecursively()) {
const QString failureMessage = QString::fromUtf8(
"Failed to recursively remove directory %1 from %2").arg(dirName, dirPath);
return { false, failureMessage };
}
}
return { true, QString() };
}
Usage:
const FileOperationResult removeResult = removeDirContents(path);
if (!removeResult.success)
qWarning() << removeResult.errorMessage;
This is how I would do it:
QString path = "name-of-directory";
QDir dir(path);
dir.setNameFilters(QStringList() << "*.txt");
dir.setFilters(QDir::Files);
while(dir.entryList().size() > 0){
dir.remove(dir.entryList().first());
}
Other variant of rreeves's code:
QDir dir("/path/to/file");
dir.setNameFilters(QStringList() << "*.*");
dir.setFilter(QDir::Files);
for(const QString &dirFile: dir.entryList()) {
dir.remove(dirFile);
}
You can achieve this without using Qt: to do so, opendir, readdir, unlink, and even rmdir will be your friends. It's easy to use, just browse the man pages ;).