简体   繁体   中英

Debug assertion (invalid comparator) when sorting in a QTreeWidget

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 in false regardless of the text(0) s. I know this VS error and it results from an assert which checks !(B < A) for A < 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);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM