How to sort item names in treeview alphabetically ignorent of the case?
-
Hi, Guys
Below is my treeview code, and I want sort to sort the directory keys alphabetically whatever whether they start with a capital letter or not, for example, the "auto-update" should be listed right after the "Audio", how to implement this? Thanks.
RegistryTreeView::RegistryTreeView(Registry &inRegistry, QWidget *inParent) { mModel = new RegistryItemModel; mModel->setRegistry(&inRegistry); mTreeView = new QTreeView; mTreeView->setContextMenuPolicy(Qt::DefaultContextMenu); mTreeView->setModel(mModel); mTreeView->setItemDelegate(new RegistryItemDelegate(mModel)); mTreeView->installEventFilter(new AutoSelectEventFilter(this)); mainLayout->addWidget(mTreeView); }
image url)
-
@MNGL
You must either interpose aQSortFilterProxyModel
between your model and theQTreeView
so that you can usesetSortCaseSensitivity(Qt::CaseInsensitive)
(e.g. https://stackoverflow.com/questions/50693571/how-to-sort-qtableview-ignoring-case) or you could override the virtualQAbstractItemModel::sort()
to implement your own case-insensitive sorting. If you do the latter be careful to maintain the correct tree structure, i.e. sorting only on siblings of each node separately. -
Thanks, @JonB
I tried the option 1, it worked, but it did not work with code in BOLD:
Is there any way to make the setItemDelegate to work with QSortFilterProxyModel object?RegistryTreeView::RegistryTreeView(Registry &inRegistry, QWidget *inParent) { mModel = new RegistryItemModel; mModel->setRegistry(&inRegistry); QSortFilterProxyModel *ProxyModel = new QSortFilterProxyModel(this); ProxyModel->setSourceModel(mModel); ProxyModel->setSortCaseSensitivity(Qt::CaseInsensitive); ProxyModel->sort(0, Qt::AscendingOrder); mTreeView = new QTreeView; mTreeView->setContextMenuPolicy(Qt::DefaultContextMenu); mTreeView->setModel(ProxyModel); **mTreeView->setItemDelegate(new RegistryItemDelegate(mModel));** //this line will cause abend. mTreeView->installEventFilter(new AutoSelectEventFilter(this)); mainLayout->addWidget(mTreeView); }
class RegistryItemDelegate : public QStyledItemDelegate { Q_OBJECT; public: RegistryItemDelegate(RegistryItemModel *inModel, QObject *inParent=NULL); //RegistryItemDelegate(QSortFilterProxyModel *inModel, QObject *inParent=NULL); virtual ~RegistryItemDelegate(); protected: virtual void initStyleOption(QStyleOptionViewItem *inOption, const QModelIndex &inIndex) const; private: RegistryItemModel *mModel; QColor mModifiedColor; QIcon mFolderIcon; };
-
@MNGL What's your
RegistryItemModel
's base class?
If it is subclassed fromQStandardItemModel
, I'd just add one custom role for sorting, something likeconst int sort_role = Qt::UserRole + 1; RegistryItemModel() { ... setSortRole(sort_role); ... }
And save
toLower()
of the original text in every item'ssort_role
data -
@MNGL said in How to sort item names in treeview alphabetically ignorent of the case?:
**mTreeView->setItemDelegate(new RegistryItemDelegate(mModel));** //this line will cause abend.
I don't know what
abend
means. Find out whether there is a problem with thenew RegistryItemDelegate(mModel)
or with themTreeView->setItemDelegate()
. -
class RegistryItemModel : public QAbstractItemModel
{
Q_OBJECT;public:
RegistryItemModel(QWidget *parent=NULL);
virtual ~RegistryItemModel();
......
}if I don't comment out following line, the program will crash before the Main Window is launched.
mTreeView->setItemDelegate(new RegistryItemDelegate(mModel));
-
@MNGL said in How to sort item names in treeview alphabetically ignorent of the case?:
Thanks, @JonB JonB
QAbstractItemModel does not have a function called setSortRole.It was @Bonnie who suggested that, if you had been using
QStandardItemModel
.Here is the crash screenshot:
I'm not sure of the reason. It comes in your
RegistryItemDelegate::initStyleOption()
override, whose code so far you have steadfastly refused to show. When you create it you pass itmModel
(I don't know why, I don't think you should be doing this), which is your source model. But the treeview is attached to theQSortFilterProxyModel
model. At a guess, theQModelIndex &inIndex
being passed is an index into the proxy model, but you are using it to index into the source model?? -
class RegistryItemDelegate : public QStyledItemDelegate { Q_OBJECT; public: //RegistryItemDelegate(RegistryItemModel *inModel, QObject *inParent=NULL); RegistryItemDelegate(QSortFilterProxyModel *mModel, QObject *inParent=NULL); virtual ~RegistryItemDelegate(); protected: virtual void initStyleOption(QStyleOptionViewItem *inOption, const QModelIndex &inIndex) const; private: //RegistryItemModel *mModel; QSortFilterProxyModel *mModel; QColor mModifiedColor; QIcon mFolderIcon; }; void RegistryItemDelegate::initStyleOption(QStyleOptionViewItem *inOption, const QModelIndex &inIndex) const { QStyledItemDelegate::initStyleOption(inOption, inIndex); const Node *node = mModel->node(inIndex); //error C2039: 'node' : is not a member of 'QSortFilterProxyModel' if(node == NULL) return; if(!node->isDefault()) inOption->palette.setColor(QPalette::Text, mModifiedColor); if(node->nodeType() == eRegDir && inOption->version == 4) { ((QStyleOptionViewItemV4*)inOption)->features |= QStyleOptionViewItemV2::HasDecoration; ((QStyleOptionViewItemV4*)inOption)->icon = mFolderIcon; } }
if I change the type of mModel from RegistryItemModel to QSortFilterProxyModel, I got following error:
error C2039: 'node' : is not a member of 'QSortFilterProxyModel'
-
@MNGL
OK. But I still don't know why you pass amModel
parameter to your delegate. I would be getting the model from theQModelIndex &inIndex()
passed toinitStyleOption()
.If your screenshot shows it is crashing on the
node->isDefault()
line, what is aNode
, how doesmModel->node(inIndex)
work, what isNode::isDefault()
? Have you compiled for Debug with no code optimizations? Just in case the line is misleading,Q_ASSERT(mModel)
. Otherwise it looks likenode
is0
/nullptr
for theexception at 0x00000000
, though you test for that, so presumably it can't be....BTW, you have not said, but are you still using Qt4 (it looks like you are), not Qt5/6??
-
@JonB
strikethrough textit's obviously that object of QSortFilterProxyModel cannot replace the mModel of RegistryItemModel.
I'm using Qt 4.8.7, and what about override the QAbstractItemModel::sort() to implement your own case-insensitive sorting, where can find a code example? -
Here is the code change that fixed the crash:
void RegistryItemDelegate::initStyleOption(QStyleOptionViewItem *inOption, const QModelIndex &inIndex) const { QStyledItemDelegate::initStyleOption(inOption, inIndex); //const Node *node = mModel->node(inIndex); const Node* node = nullptr; //code change start QModelIndex sourceIndex = inIndex; auto proxyModel = dynamic_cast<const QAbstractProxyModel*>(sourceIndex.model()); //We map the index back to its source as many times as needed. //We expect to do it once for now but that may change in the future. while (proxyModel) { sourceIndex = proxyModel->mapToSource(sourceIndex); proxyModel = dynamic_cast<const QAbstractProxyModel*>(sourceIndex.model()); } auto regModel = dynamic_cast<const RegistryItemModel*>(sourceIndex.model()) ; if (regModel) node = regModel->node(sourceIndex); //code change end if(node == NULL) return; if(!node->isDefault()) inOption->palette.setColor(QPalette::Text, mModifiedColor); if(node->nodeType() == eRegDir && inOption->version == 4) { ((QStyleOptionViewItemV4*)inOption)->features |= QStyleOptionViewItemV2::HasDecoration; ((QStyleOptionViewItemV4*)inOption)->icon = mFolderIcon; } }