I have a QLineEdit with a QRegularExpressionValidator where the allowed input is:
^(?<sign>[<>=]|>=|<=)(?<value>\d+\.?\d*)(?<unit>[mc]{0,1}m[²2]\/s|St|cSt)$
So for example:
"<15m²/s" // good
">=3.14cSt" // good
"27mm2/s" // bad
I search a way to fill a QCompleter based on this regex.
So if the cursor is on the empty QLineEdit the completer proposes:
>, <, =, >= or <=.
After the sign, propose nothing and after the last number, propose:
mm²/s, cm²/s, m²/s, St or cSt
My need is to create a QStringList by reading the allowed sign and unit part of the regex and insert this QStringList in the QCompleter because it is based on a QAbstractItemModel.
I found a workaround by subclassing QLineEdit but it is not the best solution. If someone has better, I take.
lineeditregexgroup.h:
#ifndef LINEEDITREGEXGROUP_H
#define LINEEDITREGEXGROUP_H
#include <QLineEdit>
#include <QMap>
class QCompleter;
class QStringListModel;
class QRegularExpression;
class QRegularExpressionValidator;
class LineEditRegexGroup : public QLineEdit
{
Q_OBJECT
public:
LineEditRegexGroup(const QString pattern, QWidget *parent = Q_NULLPTR);
~LineEditRegexGroup();
static QMap<QString, QStringList> mapCompleter;
public slots:
void checkValidity(const QString &text);
protected:
virtual void mouseReleaseEvent(QMouseEvent *e);
private:
QString curGroup;
QCompleter *completer;
QStringListModel *listCompleter;
QRegularExpression *regex;
QRegularExpressionValidator *validator;
};
#endif // LINEEDITREGEXGROUP_H
lineeditregexgroup.cpp:
#include "lineeditregexgroup.h"
#include <QCompleter>
#include <QStringListModel>
#include <QRegularExpression>
#include <QRegularExpressionValidator>
#include <QAbstractItemView>
QMap<QString, QStringList> LineEditRegexGroup::mapCompleter = {
{ "sign", QStringList() << "<" << ">" << "=" << "<=" << ">=" },
{ "unit", QStringList() << "mm²/s" << "cm²/s" << "m²/s" << "St" << "cSt" }
};
LineEditRegexGroup::LineEditRegexGroup(const QString pattern, QWidget *parent)
: QLineEdit(parent)
{
completer = new QCompleter(this);
listCompleter = new QStringListModel(completer);
regex = new QRegularExpression(pattern, QRegularExpression::NoPatternOption);
validator = new QRegularExpressionValidator(*regex, this);
completer->setModel(listCompleter);
completer->setCompletionMode(QCompleter::UnfilteredPopupCompletion);
setCompleter(completer);
setValidator(validator);
curGroup = regex->namedCaptureGroups().at(1);
connect(this, SIGNAL(textEdited(QString)), this, SLOT(checkValidity(QString)));
}
LineEditRegexGroup::~LineEditRegexGroup()
{
// dtor ...
}
void LineEditRegexGroup::checkValidity(const QString &text)
{
bool valid = true;
int nbCapture = 0;
QRegularExpressionMatch match = regex->match(text);
for (int i=1; i<=regex->captureCount() && valid; i++){
/* +1 to check only groups, not the global string */
valid &= !match.captured(i).isEmpty();
if (valid)
nbCapture++;
curGroup = regex->namedCaptureGroups().at(i);
if (curGroup == "value")
curGroup = regex->namedCaptureGroups().at(i-1);
}
if (nbCapture < regex->captureCount()){
QStringList new_model = mapCompleter.value(curGroup);
if (curGroup == regex->namedCaptureGroups().at(regex->captureCount())){
new_model.replaceInStrings(QRegularExpression("^(.*)$"), text+"\\1");
}
listCompleter->setStringList(new_model);
completer->complete();
}
}
void LineEditRegexGroup::mouseReleaseEvent(QMouseEvent *e)
{
QLineEdit::mouseReleaseEvent(e);
if (text().isEmpty())
checkValidity("");
}
And call it like this:
new LineEditRegexGroup(
"^(?:(?<sign>[<>=]|>=|<=|)"
"(?:(?<value>\\d+\\.?\\d*)"
"(?:(?<unit>[mc]{0,1}m[²2]\\/s|St|cSt))?)?)?$",
parent
);
Result:
Related
Let's consider this tree data :
Root
|-v A1
| |-- textA
|
|-v B1
| |-- textB
When searching "A1" I want the A1 item NOT expanded (but expandable to see the children):
Root
|-> A1
When searching "textA" I want the A1 item expanded (to see the matched child):
Root
|-v A1
| |-- textA
The (standard) filtering provided by QSortFilterProxyModel works fine, but I don't find how to implement the "expand when needed" thing.
I tried some stupid code, and it didn't work:
bool MySortFilterProxyModel::filterAcceptsRow(
int sourceRow,
const QModelIndex &sourceParent
) const {
bool result = QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent);
if (m_tree) {
// if (result)
m_tree->expand(sourceParent);
}
return result;
}
I think, that the following solution might help you a bit.
I consider it a sane way to expand the items, if they are just few children having the name being searched for. An unresolved issue might be the folding of children, if one changes the search field. Type for example C-0-0-0 in the search field to understand the behavior of my solution.
#include <QApplication>
#include <QTreeView>
#include <QDebug>
#include <QVBoxLayout>
#include <QLineEdit>
#include <QPushButton>
#include <QStandardItemModel>
#include <QSortFilterProxyModel>
int main(int argc, char **args)
{
QApplication app(argc, args);
auto frame = new QFrame;
frame->setLayout(new QVBoxLayout);
auto model = new QStandardItemModel;
for (auto i=0; i<10; i++)
{
auto item = new QStandardItem(QString("A-%1").arg(i));
model->appendRow(item);
for (auto j=0; j<10; j++)
{
auto item2 = new QStandardItem(QString("B-%1-%2").arg(i).arg(j));
item->appendRow(item2);
for (auto k=0; k<10; k++)
{
auto item3 = new QStandardItem(QString("C-%1-%2-%3").arg(i).arg(j).arg(k));
item2->appendRow(item3);
}
}
}
auto proxyModel = new QSortFilterProxyModel;
proxyModel->setSourceModel(model);
proxyModel->setRecursiveFilteringEnabled(true);
auto view = new QTreeView;
view->setModel(proxyModel);
frame->layout()->addWidget(view);
auto edit = new QLineEdit;
frame->layout()->addWidget(edit);
frame->show();
QObject::connect(edit, &QLineEdit::textChanged, [&](auto test) {
proxyModel->setFilterFixedString(test);
Qt::MatchFlags flags;
flags.setFlag(Qt::MatchFlag::MatchStartsWith, true);
flags.setFlag(Qt::MatchFlag::MatchWrap, true);
flags.setFlag(Qt::MatchFlag::MatchRecursive, true);
auto indexList=proxyModel->match(proxyModel->index(0,0), Qt::ItemDataRole::DisplayRole, test, -1, flags);
for (auto index : indexList)
{
auto expanderIndex = index.parent();
while (expanderIndex.isValid())
{
view->expand(expanderIndex);
expanderIndex = expanderIndex.parent();
}
}
qDebug() << indexList.size();
});
app.exec();
}
Improved Solution
The following improved solution uses just the found indices by the model without the possible different searching for indices provided by match.
main.cpp
#include <QApplication>
#include <QTreeView>
#include <QDebug>
#include <QVBoxLayout>
#include <QLineEdit>
#include <QPushButton>
#include <QStandardItemModel>
#include <QSortFilterProxyModel>
#include "MyProxyModel.h"
int main(int argc, char **args)
{
QApplication app(argc, args);
auto frame = new QFrame;
frame->setLayout(new QVBoxLayout);
auto model = new QStandardItemModel;
for (auto i=0; i<10; i++)
{
auto item = new QStandardItem(QString("A-%1").arg(i));
model->appendRow(item);
for (auto j=0; j<10; j++)
{
auto item2 = new QStandardItem(QString("B-%1-%2").arg(i).arg(j));
item->appendRow(item2);
for (auto k=0; k<10; k++)
{
auto item3 = new QStandardItem(QString("C-%1-%2-%3").arg(i).arg(j).arg(k));
item2->appendRow(item3);
}
}
}
auto proxyModel = new MyProxyModel;
proxyModel->setSourceModel(model);
proxyModel->setRecursiveFilteringEnabled(true);
auto view = new QTreeView;
view->setModel(proxyModel);
frame->layout()->addWidget(view);
auto edit = new QLineEdit;
frame->layout()->addWidget(edit);
frame->show();
QObject::connect(edit, &QLineEdit::textChanged, [&](auto test) {
proxyModel->setFilterFixedString(test);
if (test == "") return;
view->collapseAll();
QList<QModelIndex> acceptedIndices = proxyModel->findIndices();
for (auto index : acceptedIndices)
{
auto expanderIndex = index.parent();
while (expanderIndex.isValid())
{
view->expand(expanderIndex);
expanderIndex = expanderIndex.parent();
}
}
qDebug() << acceptedIndices.size();
});
app.exec();
}
MyProxyModel.h
#pragma once
#include <QSortFilterProxyModel>
class MyProxyModel : public QSortFilterProxyModel
{
Q_OBJECT
public:
QList<QModelIndex> findIndices() const
{
QList<QModelIndex> ret;
for (auto iter=0; iter < rowCount(); iter++)
{
auto childIndex = index(iter, 0, QModelIndex());
ret << recursivelyFindIndices(childIndex);
}
return ret;
}
bool rowAccepted(int source_row, const QModelIndex& source_parent) const
{
return filterAcceptsRow(source_row, source_parent);
}
private:
QList<QModelIndex> recursivelyFindIndices(const QModelIndex& ind) const
{
QList<QModelIndex> ret;
if (rowAccepted(ind.row(), ind.parent()))
{
ret << ind;
}
for (auto iter=0; iter<rowCount(ind); iter++)
{
ret << recursivelyFindIndices(index(iter, 0, ind));
}
return ret;
}
};
Just a few suggestions to #Aleph0 answer:
main.cpp piece:
view->collapseAll();
QList<QModelIndex> acceptedIndices = proxyModel->findIndices();
for (auto index : acceptedIndices)
{
auto expanderIndex = index.parent();
while (expanderIndex.isValid())
{
view->expand(expanderIndex);
expanderIndex = expanderIndex.parent();
}
}
In order to prevent repeated expanding it may be good to check if expanderIndex was already expanded and stop going up. In worst case scenario it will save you from O(n^2) complexity (should be linear instead).
in a similar fashion, MyProxyModel::findIndices method can be implemented without recursion to speed things up (however, modern compilers should be smart enough to unroll it)
I've two list of value. the first is list of integer and second is a list of strings. i want to display these different lists based on the last content of lineEdit. For Example when the user enter A => QCompleter show me list of strings. If the user enter A1 => QCompleter show me list of integer because the last character of input is 1.
I try like this :
void QtGuiApplication1::maFonction(QString text)
{
QString lastCaractor = text.mid(text.length() - 1, 1);
if (is_number(lastCaractor.toStdString()) == true)
{
QStringList list = { "1","2","7" };
StringCompleter->setModel(new QStringListModel(list, StringCompleter));
StringCompleter->setCompletionPrefix(lastCaractor);
}
else
{
QStringList list = { "AAAA","AA","BB","AC" };
StringCompleter->setModel(new QStringListModel(list, StringCompleter));
StringCompleter->setCompletionPrefix(lastCaractor);
}
}
bool QtGuiApplication1::is_number(const std::string& s)
{
std::string::const_iterator it = s.begin();
while (it != s.end() && std::isdigit(*it)) ++it;
return !s.empty() && it == s.end();
}
If The last character is number => QCompleter show me list = { "1","2","7" };
Else => list = { "AAAA","AA","BB","AC" };
Subclass your QLineEdit with 2 customs QCompleter
ExtendedLineEdit.h
class ExtendedLineEdit : public QLineEdit
{
Q_OBJECT
public:
explicit ExtendedLineEdit(QWidget *parent = nullptr);
void setWordCompleter(QCompleter* c);
void setNumberCompleter(QCompleter* c);
protected:
void keyPressEvent(QKeyEvent *e);
private slots:
void insertCompletionWord(const QString& txtComp);
void insertCompletionNumber(const QString& txtComp);
private:
QCompleter* m_completerWord;
QCompleter* m_completerNumber;
void showCustomCompleter(QCompleter* completer);
};
ExtendedLineEdit.cpp
ExtendedLineEdit::ExtendedLineEdit(QWidget *parent) :
QLineEdit(parent)
{
}
void ExtendedLineEdit::setWordCompleter(QCompleter *c)
{
m_completerWord = c;
m_completerWord->setWidget(this);
connect(m_completerWord, SIGNAL(activated(QString)),
this, SLOT(insertCompletionWord(QString)));
}
void ExtendedLineEdit::setNumberCompleter(QCompleter *c)
{
m_completerNumber = c;
m_completerNumber->setWidget(this);
connect(m_completerNumber, SIGNAL(activated(QString)),
this, SLOT(insertCompletionNumber(QString)));
}
void ExtendedLineEdit::keyPressEvent(QKeyEvent *e)
{
QLineEdit::keyPressEvent(e);
if (!m_completerWord || !m_completerNumber)
return;
QString lastCaractor = text().mid(text().length() - 1, 1);
bool okConvertion = false;
lastCaractor.toInt(&okConvertion);
if (okConvertion)
{
//show number completer
m_completerWord->popup()->hide();
m_completerNumber->setCompletionPrefix(lastCaractor);
showCustomCompleter(m_completerNumber);
}
else
{
//show word completer
m_completerNumber->popup()->hide();
m_completerWord->setCompletionPrefix(this->text());
showCustomCompleter(m_completerWord);
}
}
void ExtendedLineEdit::insertCompletionWord(const QString &txtComp)
{
setText(txtComp);
}
void ExtendedLineEdit::insertCompletionNumber(const QString &txtComp)
{
setText(text().mid(0, text().length() - 1) + txtComp);
}
void ExtendedLineEdit::showCustomCompleter(QCompleter *completer)
{
if (completer->completionPrefix().length() < 1)
{
completer->popup()->hide();
return;
}
QRect cr = cursorRect();
cr.setWidth(completer->popup()->sizeHintForColumn(0) + completer->popup()->verticalScrollBar()->sizeHint().width());
completer->complete(cr);
}
And using
QStringList list = { "AAAA","AA","BB","AC" };
m_wordCompleter = new QCompleter(list, this);
QStringList numbers = { "1","2","7", "15" };
m_numberCompleter = new QCompleter(numbers, this);
ui->lineEdit->setWordCompleter(m_wordCompleter);
ui->lineEdit->setNumberCompleter(m_numberCompleter);
I am creating registered qml objects and storing them in javascript array. I want to send them as QVariantList method parameter to c++. Below is the code. However first cout of Backend::sendItems method doesn't print size. Weirdly it just prints "ze" and nothing else like thread is interrupted halfway. What am I doing wrong? You can also suggest another way of achieving what I want.
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "backend.h"
#include "custom_class.h"
void register_Qml_types() {
qmlRegisterType<Backend>("customApi", 1, 0, "Backend");
qmlRegisterType<CustomClass>("customApi", 1, 0, "CustomClass");
}
int main(int argc, char **argv)
{
QGuiApplication app(argc, argv);
register_Qml_types();
QQmlApplicationEngine engine;
engine.load(QUrl("qrc:/main.qml"));
return app.exec();
}
custom_class.h
#ifndef CUSTOM_H
#define CUSTOM_H
#include <QString>
#include <QObject>
class CustomClass : public QObject
{
Q_OBJECT
Q_PROPERTY(QString name READ name WRITE setName)
public:
CustomClass(QObject* parent = 0)
: QObject(parent)
{}
CustomClass(QString name) {
name_ = name;
}
CustomClass(const CustomClass& item) {
name_ = item.name_;
}
QString name() const {
return name_;
}
void setName(QString name) {
name_ = name;
}
private:
QString name_;
};
Q_DECLARE_METATYPE(CustomClass)
#endif
backend.h
#ifndef BACKEND_H
#define BACKEND_H
#include <iostream>
#include <typeinfo>
#include <QObject>
#include <QList>
#include <QVariant>
#include "custom_class.h"
class Backend : public QObject
{
Q_OBJECT
public:
Backend(QObject* parent = nullptr)
: QObject(parent)
{}
Q_INVOKABLE void sendItems(const QVariantList& list) {
std::cout << "size " + list.size() << std::endl;
list_.clear();
for(const QVariant& variant : list) {
if(variant.canConvert<CustomClass>()) {
CustomClass* custom = new CustomClass(variant.value<CustomClass>());
list_.append(custom);
std::cout << "converted" << std::endl;
}
}
}
private:
QList<CustomClass*> list_;
};
#endif
main.qml
import QtQuick.Window 2.11
import QtQuick.Controls 1.4
import QtQuick 2.11
import customApi 1.0
Window {
id: root
visible: true
width: 500
height: 500
property var items: []
Backend {
id: backend
}
Row {
Button {
text: "button1"
onClicked: {
var item1 = Qt.createQmlObject("import customApi 1.0; CustomClass { name: \"first-name\" }", root);
var item2 = Qt.createQmlObject("import customApi 1.0; CustomClass { name: \"second-name\" }", root);
items.push(item1);
items.push(item2);
}
}
Button {
text: "button2"
onClicked: {
backend.sendItems(items);
}
}
}
}
I see you are printing:
std::cout << "size " + list.size() << std::endl;
but instead you must separate because probably it is considering size() as char.
std::cout << "size "<< list.size() << std::endl;
On the other hand QObjects are stored as a pointer, ie: CustomClass *, and also you are creating other CustomClass * not those that are in QML (I assume you want to have the same items in the view)
The solution is the next:
Q_INVOKABLE void sendItems(const QVariantList& list) {
std::cout << "size "<< list.size() << std::endl;
list_.clear();
for(const QVariant& variant : list) {
if(variant.canConvert<CustomClass *>()) {
CustomClass* custom = variant.value<CustomClass*>();
list_.append(custom);
std::cout << "converted " << custom->name().toStdString() << std::endl;
}
}
}
You can find the test project in the following link
I try to to call a method but it crashes when it trys to access a QMap member variable of AbstractIpCalculator.
I am calling like this:
AbstractIpCalculator *calculator = item_group.at(i).getCalculator();
calculator->setId(1, net_ids[1]);
ABSTRACTIPCALCULATOR_H:
#ifndef ABSTRACTIPCALCULATOR_H
#define ABSTRACTIPCALCULATOR_H
#include <QString>
#include <QDebug>
#include <QPair>
#include <QQueue>
class AbstractIpCalculator
{
public:
AbstractIpCalculator();
...
bool setId(int index, double value);
virtual QString calculate(QString) = 0;
protected:
QMap<int, double> park_netz_list;
...
private:
virtual QString calculateOctetOne(QString) = 0;
virtual QString calculateOctetTwo(QString) = 0;
virtual QString calculateOctetThree(QString) = 0;
virtual QString calculateOctetFour(QString) = 0;
};
#endif // ABSTRACTIPCALCULATOR_H
The method setParkNetzId:
bool AbstractIpCalculator::setId(int index, double value)
{
if(index >= 1)
{
qDebug() << index << value << " " << (&park_netz_list == nullptr);
park_netz_list.insert(index, value); // <--- crash!!!
return true;
}
return false;
}
There are many subclasses which extend AbstractIpCalculator. *calculator is a derived class but at this point I don't know which.
My debugger says : read access violation at: 0x0, flags=0x0 (first chance) and stops in qmap.h line 73.
I am using Qt 5.0.2.
Thank you in advance!
EDIT:
Is maybe something wrong with the setCalculator or getCalculator method?
AbstractIpCalculator *CalculatorItemGroup::getCalculator() const
{
return calculator_item;
}
void CalculatorItemGroup::setCalculator(AbstractIpCalculator &calculator_item)
{
this->calculator_item = &calculator_item;
}
initialization:
CalculatorItemGroup item;
item..setCalculator(c);
My main goal here is to redefine operator< so that I can sort my columns numerically instead of alphabetically. The code I have so far:
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
//bunch of includes...
#include <QTreeWidgetItem>
#include <QTreeWidget>
extern QSqlDatabase db;
extern QString prefix;
extern QString site;
extern QString dbname;
extern QString user;
namespace Ui {
class mainwindow;
}
class clientinfo;
class mainwindow : public QMainWindow
{
Q_OBJECT
public:
explicit mainwindow(QWidget *parent = 0);
void rPopulate();
void rbookingdisplay();
QPushButton *button;
~mainwindow();
public slots:
//slots...
private:
Ui::mainwindow *ui;
void closeEvent(QCloseEvent *close);
};
class TreeWidgetItem : public QTreeWidgetItem
{
public:
TreeWidgetItem(QTreeWidget *tree) : QTreeWidgetItem(tree) {}
TreeWidgetItem(QTreeWidget * parent, const QStringList & strings)
: QTreeWidgetItem (parent,strings) {}
bool operator< (const QTreeWidgetItem &other) const
{
int sortCol = treeWidget()->sortColumn();
int myNumber = text(sortCol).toInt();
int otherNumber = other.text(sortCol).toInt();
return myNumber < otherNumber;
}
};
#endif // MAINWINDOW_H
and in mainwindow.cpp I have ui->_display->setSortingEnabled(true);
somehow it doesn't use the redefined operator< (the redefined function is never called, it uses the predefined one). Please help.
ui->_abooking->clear();
ui->_abooking->setSortingEnabled(false);
QSqlQuery query;
query.prepare(" SELECT shownumdays, shownumpastdays FROM setting_"+ user +
" WHERE id = 1; ");
query.exec();
query.first();
int days = query.record().value("shownumdays").toInt();
int pastdays = query.record().value("shownumpastdays").toInt();
query.prepare(" SELECT `"+Columns.join("`, `")+
"`,`Currency`, `# of Room` "
" FROM abooking "
" WHERE (DATE_ADD(`Arrival Date`,INTERVAL `Nights` - 1 DAY) >= (CURRENT_DATE - "+ QString::number(pastdays) +") AND "
" (TO_DAYS(`Arrival Date`) + `Nights` - 1 - TO_DAYS(NOW())) <= "+ QString::number(days) +") ");
query.exec();
QString confirm_num = "";
bool flip = true;
while (query.next()){
if (!(confirm_num == query.record().value("Confirmation #").toString())) {
flip = (!flip);
}
QTreeWidgetItem *item = new QTreeWidgetItem();
for (int i = 0; i < Columns.length(); i++) {
if (Columns.at(i) == "Arrival Date") {
item->setText(i, query.record().value(Columns.at(i)).toDate().toString("dd-MM-yyyy"));
} else if ((Columns.at(i) == "Amount Due" || Columns.at(i) == "Paid") && (confirm_num == query.record().value("Confirmation #").toString())) {
item->setText(i, "");
} else if ((Columns.at(i) == "Arrival Time")){
item->setText(i, " " + query.record().value(Columns.at(i)).toTime().toString("hh:mm"));
} else {
item->setText(i, query.record().value(Columns.at(i)).toString());
}
if (Columns.at(i) == "Amount Due" && (!(item->text(i) == ""))) {
item->setTextColor(i, Qt::darkRed);
item->setText(i, item->text(i) + " " + query.record().value("Currency").toString());
} else if (Columns.at(i) == "Room") {
item->setText(i, query.record().value("# of Room").toString() + " " + item->text(i));
}
if (flip) {
item->setBackground(i , Qt::gray);
}
}
if ((!(confirm_num == query.record().value("Confirmation #").toString()))) {
confirm_num = query.record().value("Confirmation #").toString();
ui->_abooking->addTopLevelItem(item);
} else {
ui->_abooking->topLevelItem(ui->_abooking->topLevelItemCount() - 1)->addChild(item);
ui->_abooking->topLevelItem(ui->_abooking->topLevelItemCount() - 1)->setExpanded(true);
}
}
ui->_abooking->setSortingEnabled(true);
You're reimplementing QTreeWidgetItem with a custom class, but then you don't use it when populating the QTreeWidget.
Instead of
QTreeWidgetItem *item = new QTreeWidgetItem();
this should be:
TreeWidgetItem *item = new TreeWidgetItem();
Other than that, your code for operator < looks fine. I'm using the same and it works for me.
bool operator< (const QTreeWidgetItem &other) const
{
int sortCol = treeWidget()->sortColumn();
int myNumber = text(sortCol).toInt();
int otherNumber = other.text(sortCol).toInt();
return myNumber < otherNumber;
}
With reference to your code here above:
I think your problem is that the sort column on the widget remains constant for all QTreeWidgetItems. You have to sort on the value of the item (not the column of the widget):
Therefore the code should look like this:
bool operator< (const QTreeWidgetItem &other) const
{
Q_ASSERT( other.treeWidget() == treeWidget() );
const int col = treeWidget()->sortColumn();
const int role = Qt::DisplayRole;
return( data( col, role ).toInt() < other.data( col, role ).toInt() );
}
The cells are sorted according to the type of data you store in them. You don't need to redefine an operator for that, because QVariant will take care of the comparison for you.
For example, you should use:
item−>setData(0, `Qt::EditRole`, 10);
instead of:
item->setText(0, "10");