PDA

View Full Version : QTreeWidget Weights/Sorting



VireX
19th May 2007, 05:58
I am trying to sort my QTreeWidget, but I was wondering if there was a way to add Weights to the topLevelnodes. I mean I don't want people to sort it by say "name" column, because then it sorts my top level nodes, and the order becomes messed up.

What I want to do is keep top level nodes in a fixed order. But I want their children to be sorted normally by "name" column (which has everything).

Can I do this without subclassing and overriding sort()?
Perhaps install an event filter?
Or Is there some sort of "Weight" property I can add (Didn't see) ?

wysota
19th May 2007, 08:49
Reimplement bool operator< ( const QTreeWidgetItem & other ) const for your tree items and use the created subclass instead of QTreeWidgetItem.

VireX
20th May 2007, 02:27
Ok I reimplemented that in this way. However, will this sort "names" as well in alphabetical even if I override the original < operator? Or should I code that in too?



#include "XTreeItem.h"

bool QTreeWidgetItem::operator< ( const QTreeWidgetItem & other ) const {
int iScore, iMyScore;
iScore = 0;
iMyScore = 0;
if(other.flags() == 0){
if(other.text(0) == QString("FIRST"))iScore = 100;
if(other.text(0) == QString("SECOND"))iScore = 90;
if(other.text(0) == QString("THIRD"))iScore = 80;
if(other.text(0) == QString("FOURTH"))iScore = 70;
if(other.text(0) == QString("FIFTH"))iScore = 60;
if(other.text(0) == QString("SIXTH"))iScore = 50;
}
if(flags() == 0){
if(text(0) == QString("FIRST"))iMyScore = 100;
if(text(0) == QString("SECOND"))iMyScore = 90;
if(text(0) == QString("THIRD"))iMyScore = 80;
if(text(0) == QString("FOURTH"))iMyScore = 70;
if(text(0) == QString("FIFTH"))iMyScore = 60;
if(text(0) == QString("SIXTH"))iMyScore = 50;
}
if(iMyScore < iScore){ return true; } else { return false; }
}

#include "XTreeItem.moc"


I know I shoulda used switches and/or functions better (more OO) but still is this basically what I should do to add weights?

wysota
20th May 2007, 08:53
What original operator? You have to subclass and reimplement the method in the subclass.

VireX
20th May 2007, 15:21
That's what I did, is the code correct?

wysota
20th May 2007, 15:28
bool QTreeWidgetItem::operator< ( const QTreeWidgetItem & other ) const
This doesn't look like a subclass.

VireX
21st May 2007, 01:37
Because I forgot to change the name of the class, but yes, assume it is a subclass. You still have not commented on the actual code?

wysota
21st May 2007, 07:53
It's hard to understand it... Besides, it doesn't do much sorting... For instance it doesn't seem to compare values of items at all... Only their "flags". Is "flags" the only property of your items?

VireX
21st May 2007, 15:23
Well my toplevel nodes have 0 flags, so its only way to detect them, the rest have flags. And I'm assuming Qt will sort the rest by default (in other words my function and original function working together)

wysota
21st May 2007, 15:31
Well my toplevel nodes have 0 flags, so its only way to detect them, the rest have flags.
No. Top level nodes don't have parents. That's a way to detect them.


And I'm assuming Qt will sort the rest by default (in other words my function and original function working together)

But you never call the base class implementation so only your method gets called. That's how virtual methods work.

VireX
21st May 2007, 20:42
So how do I call it...?

Do I call it like this:
bool XTreeItem::operator< ( const QTreeWidgetItem & other ) const : QTreeWidgetItem::operator< (other) {

wysota
21st May 2007, 21:03
Call
QTreeWidgetItem::operator< ( other ); in appropriate place of your reimplementation.

VireX
21st May 2007, 21:04
Thought so, thank you, lemme try this stuff.

VireX
21st May 2007, 22:31
In file included from XTreeItem.cpp:32:
XTreeItem.moc:36: error: `staticMetaObject' is not a member of `QTreeWidgetItem'

XTreeItem.moc: In member function `virtual void* XTreeItem::qt_metacast(const char*)':
XTreeItem.moc:50: error: `qt_metacast' is not a member of `QTreeWidgetItem'
XTreeItem.moc: In member function `virtual int XTreeItem::qt_metacall(QMetaObject::Call, int, void**)':
XTreeItem.moc:55: error: `qt_metacall' is not a member of `QTreeWidgetItem'

Hmmmmmm very odd errors...

H FILE


#include <QtGui>

class XTreeItem : public QTreeWidgetItem {
Q_OBJECT
public:
XTreeItem(QTreeWidget * parent, int type);
XTreeItem(XTreeItem * parent, int type);
virtual bool operator< ( const XTreeItem & other ) const;
};


CPP FILE:


#include "XTreeItem.h"
XTreeItem::XTreeItem(QTreeWidget * parent, int type = Type ){
QTreeWidgetItem(parent, type);
}
XTreeItem::XTreeItem(XTreeItem * parent, int type = Type ){
QTreeWidgetItem(parent, type);
}
bool XTreeItem::operator< ( const XTreeItem & other ) const {
int iScore, iMyScore;
iScore = 0;
iMyScore = 0;
if(other.flags() == 0){
if(other.text(0) == QString("F"))iScore = 100;
if(other.text(0) == QString("S"))iScore = 90;
if(other.text(0) == QString("T"))iScore = 80;
if(other.text(0) == QString("F_"))iScore = 70;
if(other.text(0) == QString("F__"))iScore = 60;
if(other.text(0) == QString("S_"))iScore = 50;
}
if(flags() == 0){
if(text(0) == QString("F"))iMyScore = 100;
if(text(0) == QString("S"))iMyScore = 90;
if(text(0) == QString("T"))iMyScore = 80;
if(text(0) == QString("F_"))iMyScore = 70;
if(text(0) == QString("F__"))iMyScore = 60;
if(text(0) == QString("S_"))iMyScore = 50;
}
QTreeWidgetItem::operator< ( other );
if(iMyScore < iScore){ return true; } else { return false; }
}

#include "XTreeItem.moc"

wysota
21st May 2007, 22:56
1. The item doesn't inherit QObject so it can't contain Q_OBJECT macro
2. This code doesn't make any sense. You call the base class implementation of the operator but you don't do anything with the return value, so what's the point of calling it in the first place? The base implementation will return a boolean value telling you if the current item is smaller than the other in terms understood by the base class.

VireX
21st May 2007, 23:01
1. I thought any QWidget was a QObject and therefore I needed Q_OBJECT right? Or do I not even need that?
2. Yes I realized that after I posted heh.
if(iMyScore < iScore){ return true; } else { return QTreeWidgetItem::operator< ( other ); }

wysota
21st May 2007, 23:23
1. I thought any QWidget was a QObject and therefore I needed Q_OBJECT right? Or do I not even need that?
QTreeWidgetItem is not a widget. QTreeWidget is.

VireX
21st May 2007, 23:43
The name is misleading :).

wysota
22nd May 2007, 00:41
No, it's not. All "items" are not widgets.

VireX
22nd May 2007, 04:48
This is becoming very very frustrating... And you wonder why I avoid subclassing...

CMain.cpp:322: error: no matching function for call to `XTreeItem::XTreeItem(XTreeItem*&)'
XTreeItem.h:7: note: candidates are: XTreeItem::XTreeItem(XTreeItem*, int)
XTreeItem.h:6: note: XTreeItem::XTreeItem(const XTreeItem&)
XTreeItem.h:5: note: XTreeItem::XTreeItem(QTreeWidget*)

CMain.cpp:329: error: no matching function for call to `XTreeItem::XTreeItem(XTreeItem*&)'
XTreeItem.h:7: note: candidates are: XTreeItem::XTreeItem(XTreeItem*, int)
XTreeItem.h:6: note: XTreeItem::XTreeItem(const XTreeItem&)
XTreeItem.h:5: note: XTreeItem::XTreeItem(QTreeWidget*)
CMain.cpp:340: error: no matching function for call to `XTreeItem::XTreeItem(XTreeItem*&)'
XTreeItem.h:7: note: candidates are: XTreeItem::XTreeItem(XTreeItem*, int)
XTreeItem.h:6: note: XTreeItem::XTreeItem(const XTreeItem&)
XTreeItem.h:5: note: XTreeItem::XTreeItem(QTreeWidget*)

CMain.cpp:351: error: no matching function for call to `XTreeItem::XTreeItem(XTreeItem*&)'
XTreeItem.h:7: note: candidates are: XTreeItem::XTreeItem(XTreeItem*, int)
XTreeItem.h:6: note: XTreeItem::XTreeItem(const XTreeItem&)
XTreeItem.h:5: note: XTreeItem::XTreeItem(QTreeWidget*)
CLobby.cpp:352: error: no matching function for call to `XTreeItem::XTreeItem(XTreeItem*&)'
XTreeItem.h:7: note: candidates are: XTreeItem::XTreeItem(XTreeItem*, int)
XTreeItem.h:6: note: XTreeItem::XTreeItem(const XTreeItem&)
XTreeItem.h:5: note: XTreeItem::XTreeItem(QTreeWidget*)
CMain.cpp:353: error: no matching function for call to `XTreeItem::XTreeItem(XTreeItem*&)'
XTreeItem.h:7: note: candidates are: XTreeItem::XTreeItem(XTreeItem*, int)
XTreeItem.h:6: note: XTreeItem::XTreeItem(const XTreeItem&)
XTreeItem.h:5: note: XTreeItem::XTreeItem(QTreeWidget*)
CMain.cpp:354: error: no matching function for call to `XTreeItem::XTreeItem(XTreeItem*&)'
XTreeItem.h:7: note: candidates are: XTreeItem::XTreeItem(XTreeItem*, int)
XTreeItem.h:6: note: XTreeItem::XTreeItem(const XTreeItem&)
XTreeItem.h:5: note: XTreeItem::XTreeItem(QTreeWidget*)

CMain.cpp:355: error: no matching function for call to `XTreeItem::XTreeItem(XTreeItem*&)'
XTreeItem.h:7: note: candidates are: XTreeItem::XTreeItem(XTreeItem*, int)
XTreeItem.h:6: note: XTreeItem::XTreeItem(const XTreeItem&)
XTreeItem.h:5: note: XTreeItem::XTreeItem(QTreeWidget*)
CMain.cpp:356: error: no matching function for call to `XTreeItem::XTreeItem(XTreeItem*&)'
XTreeItem.h:7: note: candidates are: XTreeItem::XTreeItem(XTreeItem*, int)
XTreeItem.h:6: note: XTreeItem::XTreeItem(const XTreeItem&)
XTreeItem.h:5: note: XTreeItem::XTreeItem(QTreeWidget*)

code for H file:


#include <QtGui>

class XTreeItem : public QTreeWidgetItem {
public:
XTreeItem(QTreeWidget * parent);
XTreeItem(const XTreeItem & other);
XTreeItem(XTreeItem * parent, int type);
virtual bool operator< ( const XTreeItem & other ) const;
};


CPPPPPPPPPP


#include "XTreeItem.h"
XTreeItem::XTreeItem(QTreeWidget * parent){
QTreeWidgetItem(parent, Type);
}
XTreeItem::XTreeItem(XTreeItem * parent, int type = Type){
QTreeWidgetItem(parent, type);
}
XTreeItem::XTreeItem(const XTreeItem & other){
QTreeWidgetItem(parent);
}
bool XTreeItem::operator< ( const XTreeItem & other ) const {
int iScore, iMyScore;
iScore = 0;
iMyScore = 0;
if(other.flags() == 0){
if(other.text(0) == QString("F"))iScore = 100;
if(other.text(0) == QString("S"))iScore = 90;
}
if(flags() == 0){
if(text(0) == QString("F"))iMyScore = 100;
if(text(0) == QString("S"))iMyScore = 90;
}
if(iMyScore < iScore){ return true; } else { return QTreeWidgetItem::operator< ( other ); }
}

Please help I give up.... I tried everything, I transmit those headers to QTreeWidgetItem (with same arguments).

All I try to do is:
XTreeItem* t = new XTreeItem(MainList); (MainList is a QTreeWidget*).
That doesn't work so I change the code, and when I do now this doesn't work:
XTreeItem* bee = new XTreeItem(First); (First is a XTreeItem*)

wysota
22nd May 2007, 09:28
It has to be like this:

XTreeItem::XTreeItem(QTreeWidget * parent) : QTreeWidgetItem(parent, Type){}

This is the way to call the base class constructor. As for the rest, the compiler tells you you're using non-existent methods and suggest ones that are available.

Please search the forum. I'm sure we provided code for subclassing tree widget items a few times, so you might want to take a look at our code.

VireX
23rd May 2007, 06:14
Yeah I was gonna do it that way, but I thought what would be the difference if i did it this way... :S. Hmm it seems though my code isn't working, can you verify that?

Its not sorting according to weights... any reason for this? Can anyone try it on a single treewidget?

VireX
24th May 2007, 05:41
Any Ideas on the weight system, it doesn't seem to do the trick like you said. Doesn't seem like my operator < even getting called.

wysota
24th May 2007, 09:28
This is an example of a working reimplementation.

class Item : public QTreeWidgetItem {
public:
Item(const QString &s) : QTreeWidgetItem(QStringList() << s){}
bool operator< ( const QTreeWidgetItem & other ) const{
QRegExp rx("[A-z]+([0-9]+)");
int one = -1;
int two = -1;
if(rx.exactMatch(text(0))){
one = rx.cap(1).toInt();
}
if(rx.exactMatch(other.text(0))){
two = rx.cap(1).toInt();
}
if(one % 2){ // odd
if(two % 2){
return one < two;
} else return true;
} else { // even
if(two % 2){
return false;
} else return one < two;
}
return QTreeWidgetItem::operator<(other);
}
};

VireX
24th May 2007, 22:56
Ok so I did nothing wrong, then why is it not working?

wysota
24th May 2007, 23:07
I don't know that. If your method doesn't get called, it probably means the signature is incorrect. Could you show the item class header?

VireX
24th May 2007, 23:14
#ifndef _X_TREEITEM
#define _X_TREEITEM
#include <QtGui>
#include "CGUI.h"
class XTreeItem : public QTreeWidgetItem {
public:
XTreeItem(QTreeWidget * parent);
XTreeItem(const XTreeItem & other);
XTreeItem(XTreeItem * parent);
virtual bool operator< ( const XTreeItem & other ) const;
};
#endif

wysota
24th May 2007, 23:49
Here we go... Should be:

#ifndef _X_TREEITEM
#define _X_TREEITEM
#include <QtGui>
#include "CGUI.h"
class XTreeItem : public QTreeWidgetItem {
public:
XTreeItem(QTreeWidget * parent);
XTreeItem(const XTreeItem & other);
XTreeItem(XTreeItem * parent);
bool operator< ( const QTreeWidgetItem & other ) const;
};
#endif