I've the following custom QTreeWidgetItem
that I use in my QTreeWidget
:
#ifndef FEDERATELISTITEM_HPP_
#define FEDERATELISTITEM_HPP_
#include <QTreeWidgetItem>
class FederateListItem : public QTreeWidgetItem {
public:
enum Type : int {
Federate = 101,
FederateNamespace = 102
};
public:
FederateListItem(QTreeWidget* parent, Type type);
FederateListItem(QTreeWidgetItem* parent, Type type);
public:
bool operator<(const QTreeWidgetItem& other) const;
bool operator==(const QTreeWidgetItem& other) const;
};
#endif // !FEDERATELISTITEM_HPP_
#include "FederateListItem.hpp"
///////////////////////////////////////////////////////////////////////////////
// CONSTANTS SECTION //
///////////////////////////////////////////////////////////////////////////////
const QString FederateNamespaceCloseIcon{ ":/icons/FederateNamespaceActive.png" };
const QString FederateIcon(":/icons/FederateActive.png");
///////////////////////////////////////////////////////////////////////////////
// PUBLIC SECTION //
///////////////////////////////////////////////////////////////////////////////
FederateListItem::FederateListItem(QTreeWidget* parent, Type type) :
QTreeWidgetItem(parent, static_cast<int>(type)) {
switch (type) {
case Type::Federate: {
setIcon(0, QIcon(FederateIcon));
} break;
case Type::FederateNamespace: {
setIcon(0, QIcon(FederateNamespaceCloseIcon));
} break;
default: {
}
}
}
FederateListItem::FederateListItem(QTreeWidgetItem* parent, Type type) :
QTreeWidgetItem(parent, static_cast<int>(type)) {
switch (type) {
case Type::Federate: {
setIcon(0, QIcon(FederateIcon));
} break;
case Type::FederateNamespace: {
setIcon(0, QIcon(FederateNamespaceCloseIcon));
} break;
default: {
}
}
}
///////////////////////////////////////////////////////////////////////////////
// PUBLIC MEMBER OPERATORS SECTION //
///////////////////////////////////////////////////////////////////////////////
bool FederateListItem::operator<(const QTreeWidgetItem& other) const {
if ((type() == Type::FederateNamespace) && (other.type() == Type::Federate)) {
return true;
}
return text(0) < other.text(0);
}
bool FederateListItem::operator==(const QTreeWidgetItem& other) const {
return (type() == other.type()) && (text(0) == other.text(0));
}
Basically I need to use two types of items: a federate
one that's a leaf, and a federatenamespace
one that can contains federate
and federatenamespace
child items.
I want to sort them so, at any level, I have first all federatenamespace
items, and then federates
one. Like in Windows Explorer that I see first folders and then files.
In order to accomplish this in my custom item I've added some operator methods: first I check the type of the item and I try to give precedente to FederateNamespace
items, so they should be shown first. If the type is the same, order them by their name.
Then I create the QTreeWidget
:
m_tree = new QTreeWidget(this);
m_tree->setHeaderLabels({ FederatesLabel });
m_tree->setSortingEnabled(true);
When I start to add items of the same type everything seems to work, as I can see:
The problem is that sorting does not work. You can see in images that sort is not performed. And if I try to mix elements, an assertion is raised.
The assertion is raised by Qt and says that the comparator is invalid.
What I'm doing wrong and how can I fix this?
EDIT
I've followed Scheff suggestion and with a little tweak not it works. The problem was my operator method. This works:
bool FederateListItem::operator<(const QTreeWidgetItem& other) const {
if ((type() == Type::FederateNamespace) && (other.type() == Type::Federate)) {
return false;
}
if ((type() == Type::Federate) && (other.type() == Type::FederateNamespace)) {
return true;
}
return text(0) > other.text(0);
}
My guess written in comment:
You don't consider the case that
(type() == Type::Federate) && (other.type() == Type::FederateNamespace)
which should result infalse
regardless of thetext(0)
s. I know this VS error and it results from an assert which checks!(B < A)
forA < B
to ensure that the strict order is achieved/granted by the predicate.
My proposal for a fixed less operator:
bool FederateListItem::operator<(const QTreeWidgetItem& other) const {
if (type() != other.type()) return type() == Type::FederateNamespace;
return text(0) < other.text(0);
}