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) -
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 aQSortFilterProxyModelbetween your model and theQTreeViewso 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; }; -
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_roledata -
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 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
abendmeans. 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)); -
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)); -
Thanks, @JonB JonB
QAbstractItemModel does not have a function called setSortRole.Here is the crash screenshot:
@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 theQSortFilterProxyModelmodel. At a guess, theQModelIndex &inIndexbeing passed is an index into the proxy model, but you are using it to index into the source model?? -
@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 theQSortFilterProxyModelmodel. At a guess, theQModelIndex &inIndexbeing 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'
-
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 amModelparameter 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 likenodeis0/nullptrfor 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??
-
@MNGL
OK. But I still don't know why you pass amModelparameter 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 likenodeis0/nullptrfor 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??
-
@MNGL
OK. But I still don't know why you pass amModelparameter 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 likenodeis0/nullptrfor 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; } }