Sort filenames naturally with Qt
If you want to use QCollator
to sort entries from the list of entries returned by QDir::entryList
, you can sort the result with std::sort()
:
dir.setFilter(QDir::Files | QDir::NoSymLinks);
dir.setSorting(QDir::NoSort); // will sort manually with std::sort
auto entryList = dir.entryList();
QCollator collator;
collator.setNumericMode(true);
std::sort(
entryList.begin(),
entryList.end(),
[&](const QString &file1, const QString &file2)
{
return collator.compare(file1, file2) < 0;
});
According to The Badger's comment, QCollator
can also be used directly as an argument to std::sort
, replacing the lambda, so the call to std::sort
becomes:
std::sort(entryList.begin(), entryList.end(), collator);
Natural sort of filenames with numbers issue c++
You should compare number part and then string part on equal number part.
inline int findStringPart(const QString &s)
{
...
return stringPart; //Left or Right
}
static bool naturalSortCallback(const QString &s1, const QString &s2)
{
int numberPart1 = findNumberPart(s1);
int numberPart2 = findNumberPart(s2);
QString stringPart1 = findStringPart(s1);
QString stringPart2 = findStringPart(s2);
if(numberPart1 == numberPart2)
return stringPart1 < stringPart2; //"Left" < "Right"
return numberPart1 < numberPart2;
}
How to implement a natural sort algorithm in c++?
I asked this exact question (although in Java) and got pointed to http://www.davekoelle.com/alphanum.html which has an algorithm and implementations of it in many languages.
Update 14 years later: Dave Koelle’s blog has gone off line and I can’t find his actual algorithm, but here’s an implementation.
https://github.com/cblanc/koelle-sort
(valid) QFileInfo causes segv when calling QFileInfo::filename() in std::sort
QCollater::compare(s1, s2)
returns "an integer less than, equal to, or greater than zero depending on whether s1 sorts before, with or after s2"
, hence your comparator doesn't obey strict weak ordering -- it's effectively checking the relationship 's1 != s2' rather than 's1 < s2'. That's undefined behaviour.
Try changing the sort comparator to...
std::sort(fileInfoImageList.begin(), fileInfoImageList.end(),
[&collator](const QFileInfo &a, const QFileInfo &b)
{
QString nameA = a.fileName();
QString nameB = b.fileName();
return collator.compare(nameA, nameB) < 0;
});
Is there a Qt Dialog or Widget to interactively sort a string list?
Qt already supports it, there's nothing for you to do: The standard views automatically support internal drag and drop, where items are moved around to change the order in which they are displayed.
Further quoting the documentation:
- To enable item dragging, set the view's
dragEnabled
property to true. - To allow the user to drop both internal or external items within the view, set the view's viewport()'s
acceptDrops
property to true. - To show the user where the item currently being dragged will be placed if dropped, set the view's
showDropIndicator
property. This provides the user with continuously updating information about item placement within the view. - To enable the user to move the items around within the view, we must set the list widget's dragDropMode to
QAbstractItemView::InternalMove
.
Below is a sscce that you can run to see it in action.
#include <QApplication>
#include <QListWidget>
#include <QListWidgetItem>
int main(int argc, char ** argv)
{
QApplication a(argc, argv);
QListWidget w;
w.addItem("Rosalind");
w.addItem("Celia");
w.addItem("Adam");
w.addItem("Jaques");
w.setDragEnabled(true);
w.setDropIndicatorShown(true);
w.setDragDropMode(QAbstractItemView::InternalMove);
w.show();
return a.exec();
}
Natural Sort of Directory Filenames in C++
There is a function that does exactly what you want in glibc. Unfortunately it is C, not C++, so if you can live with that here is the simplest possible solution "out of the box", without reimplementing anything and reinventing the wheel. BTW: this is exactly as ls -lv
is implemented. The most important part of it is the versionsort
function which does the natural sort for you. It is used here as a comparison function for scandir
.
The simple example below prints all files/directories in current directory sorted as you wish.
#define _GNU_SOURCE
#include <dirent.h>
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
struct dirent **namelist;
int n,i;
n = scandir(".", &namelist, 0, versionsort);
if (n < 0)
perror("scandir");
else
{
for(i =0 ; i < n; ++i)
{
printf("%s\n", namelist[i]->d_name);
free(namelist[i]);
}
free(namelist);
}
return 0;
}
C++ - Changing the sorting for custom QSortFilterProxyModel
You should call QSortFilterProxyModel::invalidate
to indicate that the current sorting is invalidated, i.e. a new sort action should be performed.
Note that calling sort
explicitly will also work when dynamicSortFilter
is false or you specify another column or order as can be seen in the code:
void QSortFilterProxyModel::sort(int column, Qt::SortOrder order)
{
Q_D(QSortFilterProxyModel);
if (d->dynamic_sortfilter && d->proxy_sort_column == column && d->sort_order == order)
return;
d->sort_order = order;
d->proxy_sort_column = column;
d->update_source_sort_column();
d->sort();
}
Qt4 QMenu items sorting
Once added, I don't think you can reorder. While you are creating though you could use the QWidget::insertAction method to place it exactly where you want it.
void QWidget::insertAction ( QAction * before, QAction * action )
Otherwise you could use QWidget::addActions. Create your list of Actions and sort it before adding to the QMenu.
void QWidget::addActions ( QList<QAction *> actions )
Sort actual QMap by key
You have several appoaches that you could take:
Store the keys as integers after converting
QString
to an integer.You can use the compare class for std::map as per the example:
You can try to use specialize this template function that QMap uses for the comparison.
main.cpp
#include <QMap>
#include <QDebug>
#include <map>
struct str_num_compare {
bool operator() (const QString& lhs, const QString& rhs) const
{return lhs.toInt()<rhs.toInt();}
};
int main()
{
QStringList stringList{"1", "10", "11", "2", "3", "4"};
QMap<int, QString> map;
foreach (const QString &string, stringList)
map.insert(string.toInt(), string);
qDebug() << "Integer key approach:" << map;
std::map<QString, QString, str_num_compare> std_map;
foreach (const QString &string, stringList)
std_map[string] = string;
qDebug() << "QString key approach with std::map:";
for (auto item : std_map)
qDebug() << item.first;
return 0;
}
main.pro
TEMPLATE = app
TARGET = main
QT = core
CONFIG += c++11
SOURCES += main.cpp
Build and Run
qmake && make && ./main
Output
Integer key approach: QMap((1, "1")(2, "2")(3, "3")(4, "4")(10, "10")(11, "11"))
QString key approach:
"1"
"2"
"3"
"4"
"10"
"11"
Related Topics
How to Omit the Double-Braces for Std::Array in C++14
Undefined Reference to Mempcy@Glibc_2.14 When Compiling on Linux
In Which Access Control Context Are Concepts Evaluated
Ordering of Using Namespace Std; and Includes
Uniform Initialization Fails to Copy When Object Has No Data Members
How to Include Data Object Files (Images, etc.) in Program and Access the Symbols
How to Parse CSV Using Boost::Spirit
Dependent Name Resolution & Namespace Std/Standard Library
C++ Regex for Overlapping Matches
C++: Where Does the Ofstream Class Save the Files To
Are the "Usual Arithmetic Conversions" and the "Integer Promotions" the Same Thing
When Should I Use the Keyword "Typename" When Using Templates
Boost::Asio + Std::Future - Access Violation After Closing Socket