Page 1 of 2 12 LastLast
Results 1 to 20 of 22

Thread: QT4: Sorting in QTreeWidget (subclass)

  1. #1
    Join Date
    Mar 2006
    Location
    The Netherlands
    Posts
    300
    Thanks
    9
    Thanked 29 Times in 29 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11

    Default QT4: Sorting in QTreeWidget (subclass)

    I've created a QTreeWidget subclass and a QTreeWidgetItem subclass. They work, except for the sorting. When I click on the headers, nothing changes except for the sorting indicator.

    setSorting is enabled, so that isn't it. Now, it doesn't even sort by string-value. But also, I'm missing a reimplementable function in QTreeWidgetItem. I suspected something like:

    virtual int QTreeWidgetItem::compare(int column); // -1, 0 or 1

    or something. Because two of the columns actually represent QDateTime variables, and I don't want them to be sorted as strings.

    So, how do I implement sorting?

    Thanks!
    "The strength of a civilization is not measured by its ability to wage wars, but rather by its ability to prevent them." - Gene Roddenberry

  2. #2
    Join Date
    Feb 2006
    Location
    Oslo, Norway
    Posts
    6,264
    Thanks
    36
    Thanked 1,519 Times in 1,389 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows Symbian S60 Maemo/MeeGo

    Default Re: QT4: Sorting in QTreeWidget (subclass)

    You can change the sorting algorithm by overriding
    virtual bool operator< ( const QTreeWidgetItem & other ) const

  3. #3
    Join Date
    Mar 2006
    Location
    The Netherlands
    Posts
    300
    Thanks
    9
    Thanked 29 Times in 29 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11

    Default Re: QT4: Sorting in QTreeWidget (subclass)

    Ooooh. Right, I suppose I can get the sorting column and sorting order with other member functions. I was thrown off because QT3 did it differently.

    Thanks!
    "The strength of a civilization is not measured by its ability to wage wars, but rather by its ability to prevent them." - Gene Roddenberry

  4. #4
    Join Date
    Mar 2006
    Location
    The Netherlands
    Posts
    300
    Thanks
    9
    Thanked 29 Times in 29 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11

    Default Re: QT4: Sorting in QTreeWidget (subclass)

    It doesn't seem to work.

    Qt Code:
    1. bool MyTreeWidgetItem::operator<(const QTreeWidgetItem & other) const {
    2. switch (treeWidget()->sortColumn()) {
    3. case 0:
    4. return _category < ((const MyTreeWidgetItem &)other)._category;
    5. case 1:
    6. return _start < ((const MyTreeWidgetItem &)other)._start;
    7. case 2:
    8. return _end < ((const MyTreeWidgetItem &)other)._end;
    9. case 3:
    10. return _note < ((const MyTreeWidgetItem &)other)._note;
    11. }
    12. return false;
    13. }
    To copy to clipboard, switch view to plain text mode 

    _start and _end are QDateTime objects. The other two are strings. All four are member vars of MyTreeWidgetItem. I only found the sortColumn() function, so I supposed that the sort order would automatically adjust to the sorting indicator.

    But it doesn't sort anything. All rows remain in place.
    "The strength of a civilization is not measured by its ability to wage wars, but rather by its ability to prevent them." - Gene Roddenberry

  5. #5
    Join Date
    Feb 2006
    Location
    Oslo, Norway
    Posts
    6,264
    Thanks
    36
    Thanked 1,519 Times in 1,389 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows Symbian S60 Maemo/MeeGo

    Default Re: QT4: Sorting in QTreeWidget (subclass)

    Did you declare the operator as public? Assure that it gets called, add a breakpoint or some debug output..
    Yep, treewidget()->sortColumn() is the correct method to find out which column is used to sort.

  6. #6
    Join Date
    Mar 2006
    Location
    The Netherlands
    Posts
    300
    Thanks
    9
    Thanked 29 Times in 29 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11

    Default Re: QT4: Sorting in QTreeWidget (subclass)

    Yes. The function is definately being used when I click the headers. Here is the whole code of both classes. Just in case I'm doing something wrong elsewhere.

    treewidget.h
    Qt Code:
    1. #ifndef TREEWIDGET_H
    2. #define TREEWIDGET_H
    3.  
    4. #include <QTreeWidget>
    5. #include <QPoint>
    6.  
    7. class TreeWidgetItem;
    8.  
    9. class TreeWidget : public QTreeWidget {
    10. Q_OBJECT
    11. public:
    12. TreeWidget(QWidget* parent = 0);
    13. TreeWidgetItem* currentItem() const;
    14. TreeWidgetItem* itemAt(const QPoint & p) const;
    15. TreeWidgetItem* itemAt(int x, int y) const;
    16. TreeWidgetItem* takeTopLevelItem(int index);
    17. TreeWidgetItem* topLevelItem(int index) const;
    18. };
    19.  
    20. #endif // TREEWIDGET_H
    To copy to clipboard, switch view to plain text mode 

    treewidget.cpp
    Qt Code:
    1. #include "treewidget.h"
    2.  
    3. #include "treewidgetitem.h"
    4.  
    5. TreeWidget::TreeWidget(QWidget * parent) : QTreeWidget(parent) {
    6. setColumnCount(4);
    7. headerItem()->setText(0, tr("Category") );
    8. headerItem()->setText(1, tr("Start") );
    9. headerItem()->setText(2, tr("End") );
    10. headerItem()->setText(3, tr("Note") );
    11. setAlternatingRowColors(true);
    12. }
    13.  
    14. TreeWidgetItem* TreeWidget::currentItem() const {
    15. return (TreeWidgetItem*)QTreeWidget::currentItem();
    16. }
    17.  
    18. TreeWidgetItem* TreeWidget::itemAt(const QPoint & p) const {
    19. return (TreeWidgetItem*)QTreeWidget::itemAt(p);
    20. }
    21.  
    22. TreeWidgetItem* TreeWidget::itemAt(int x, int y) const {
    23. return (TreeWidgetItem*)QTreeWidget::itemAt(x, y);
    24. }
    25.  
    26. TreeWidgetItem* TreeWidget::takeTopLevelItem(int index) {
    27. return (TreeWidgetItem*)QTreeWidget::takeTopLevelItem(index);
    28. }
    29.  
    30. TreeWidgetItem* TreeWidget::topLevelItem(int index) const {
    31. return (TreeWidgetItem*)QTreeWidget::topLevelItem(index);
    32. }
    To copy to clipboard, switch view to plain text mode 

    treewidgetitem.h
    Qt Code:
    1. #ifndef TREEWIDGETITEM_H
    2. #define TREEWIDGETITEM_H
    3.  
    4. #include <QTreeWidgetItem>
    5. #include <QDateTime>
    6.  
    7. class TreeWidget;
    8.  
    9. class TreeWidgetItem : public QObject, public QTreeWidgetItem {
    10. Q_OBJECT
    11. public:
    12. TreeWidgetItem(TreeWidget* parent, int type = UserType);
    13.  
    14. TreeWidgetItem* clone() const;
    15. QVariant data(int column, int role) const;
    16. void read(QDataStream & in);
    17. void setData(int column, int role, const QVariant & value);
    18. void write(QDataStream & out) const;
    19.  
    20. bool operator<(const QTreeWidgetItem & other) const;
    21.  
    22. private:
    23. QString _category;
    24. QDateTime _start;
    25. QDateTime _end;
    26. QString _note;
    27. };
    28.  
    29. #endif // TREEWIDGETITEM_H
    To copy to clipboard, switch view to plain text mode 

    treewidgetitem.cpp
    Qt Code:
    1. #include "treewidgetitem.h"
    2. #include "treewidget.h"
    3.  
    4. TreeWidgetItem::TreeWidgetItem(TreeWidget * parent, int type) : QTreeWidgetItem((QTreeWidget*)parent, type) {
    5. } // intentionally empty
    6.  
    7. TreeWidgetItem* TreeWidgetItem::clone() const {
    8. return NULL; // FIXME: Create this function
    9. }
    10.  
    11. QVariant TreeWidgetItem::data(int column, int role) const {
    12. if (role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::ToolTipRole) {
    13. if (column == 0)
    14. return QVariant(_category);
    15.  
    16. if (column == 1)
    17. return QVariant(_start.toString());
    18.  
    19. if (column == 2)
    20. return (_end.isValid() ? QVariant(_end.toString()) : QVariant(QString("<running>")));
    21.  
    22. if (column == 3)
    23. return QVariant(_note);
    24. }
    25.  
    26. if (role == Qt::UserRole) {
    27. if (column == 0)
    28. return QVariant(_category);
    29.  
    30. if (column == 1)
    31. return QVariant(_start);
    32.  
    33. if (column == 2)
    34. return QVariant(_end);
    35.  
    36. if (column == 3)
    37. return QVariant(_note);
    38. }
    39.  
    40. return QVariant();
    41. }
    42.  
    43. void TreeWidgetItem::read(QDataStream & /*in*/) {
    44. // FIXME: Create this function
    45. }
    46.  
    47. void TreeWidgetItem::setData(int column, int role, const QVariant & value) {
    48. if (role == Qt::EditRole) {
    49. if (column == 0)
    50. _category = value.toString();
    51.  
    52. if (column == 1)
    53. _start = (QDateTime::fromString(value.toString()).isValid() ? QDateTime::fromString(value.toString()) : _start);
    54.  
    55. if (column == 2)
    56. _end = (QDateTime::fromString(value.toString()).isValid() ? QDateTime::fromString(value.toString()) : _end);
    57.  
    58. if (column == 3)
    59. _note = value.toString();
    60. }
    61.  
    62. if (role == Qt::UserRole) {
    63. if (column == 0)
    64. _category = value.toString();
    65.  
    66. if (column == 1)
    67. _start = value.toDateTime();
    68.  
    69. if (column == 2)
    70. _end = value.toDateTime();
    71.  
    72. if (column == 3)
    73. _note = value.toString();
    74. }
    75. }
    76.  
    77. void TreeWidgetItem::write(QDataStream & /*out*/) const {
    78. // FIXME: Create this function
    79. }
    80.  
    81. #include <iostream>
    82. using namespace std;
    83.  
    84. bool TreeWidgetItem::operator<(const QTreeWidgetItem & other) const {
    85. cerr << "TEST" << endl;
    86. switch (treeWidget()->sortColumn()) {
    87. case 0:
    88. return _category < ((const TreeWidgetItem &)other)._category;
    89. case 1:
    90. return _start < ((const TreeWidgetItem &)other)._start;
    91. case 2:
    92. return _end < ((const TreeWidgetItem &)other)._end;
    93. case 3:
    94. return _note < ((const TreeWidgetItem &)other)._note;
    95. }
    96. return false;
    97. }
    To copy to clipboard, switch view to plain text mode 

    I inherited QObject too, because I want to add signals and slots later.

    So, what am I doing wrong?

    Thanks!
    "The strength of a civilization is not measured by its ability to wage wars, but rather by its ability to prevent them." - Gene Roddenberry

  7. #7
    Join Date
    Mar 2006
    Posts
    10
    Qt products
    Qt3
    Platforms
    Unix/X11

    Default Re: QT4: Sorting in QTreeWidget (subclass)

    you dont need to inherit QObject becausse the Q_OBJECT macro does that

  8. #8
    Join Date
    Mar 2006
    Location
    The Netherlands
    Posts
    300
    Thanks
    9
    Thanked 29 Times in 29 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11

    Default Re: QT4: Sorting in QTreeWidget (subclass)

    Oh? Is that new in QT4, because as I recall, QT3 needed both.
    "The strength of a civilization is not measured by its ability to wage wars, but rather by its ability to prevent them." - Gene Roddenberry

  9. #9
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: QT4: Sorting in QTreeWidget (subclass)

    Quote Originally Posted by incubator
    you dont need to inherit QObject becausse the Q_OBJECT macro does that
    Q_OBJECT just puts some methods in class definition and marks the class for MOC to process. It doesn't cause QObject to be inherited, you have to explicitely inherit it.

  10. #10
    Join Date
    Feb 2006
    Location
    Oslo, Norway
    Posts
    6,264
    Thanks
    36
    Thanked 1,519 Times in 1,389 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows Symbian S60 Maemo/MeeGo

    Default Re: QT4: Sorting in QTreeWidget (subclass)

    I think it might be your TreeWidget::data() and TreeWidget::setData() implementations which mess it up..
    You could try re-formatting the bodies of those functions to something like this:
    Qt Code:
    1. QVariant TreeWidgetItem::data(int column, int role) const {
    2. if (role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::ToolTipRole)
    3. ...
    4. else if (role == Qt::UserRole)
    5. ...
    6. else
    7. return QTreeWidgetItem::data(column, role);
    8. }
    9.  
    10. void TreeWidgetItem::setData(int column, int role, const QVariant & value) {
    11. if (role == Qt::EditRole)
    12. ..
    13. else if (role == Qt::UserRole)
    14. ..
    15. else
    16. QTreeWidgetItem::setData(column, role, value);
    17. }
    To copy to clipboard, switch view to plain text mode 
    It's important that all needed roles become handled correctly. So you may call base class implementation in case you're not interested of some specific role.

    A side note:
    In my opinion, overriding data() and setData() for this purpose is a bit futile.

    You could use setText() for all TreeWidgetItem columns, even for the datetimes.
    Then in the compare operator you simply handle those 2 datetime columns explicitly:
    Qt Code:
    1. bool TreeWidgetItem::operator<(const QTreeWidgetItem & other) const
    2. {
    3. int column = treeWidget()->sortColumn();
    4. if (column == 1 || column == 2)
    5. {
    6. QDateTime thisDate = QDateTime::fromString(text(column));
    7. QDateTime otherDate = QDateTime::fromString(other.text(column));
    8. return thisDate < otherDate;
    9. }
    10. return QTreeWidgetItem::operator <(other);
    11. }
    To copy to clipboard, switch view to plain text mode 
    By this way you could just forget complicated data() and setData()...

  11. #11
    Join Date
    Mar 2006
    Location
    The Netherlands
    Posts
    300
    Thanks
    9
    Thanked 29 Times in 29 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11

    Default Re: QT4: Sorting in QTreeWidget (subclass)

    Ah. Call the base class implementation. That makes sense. I'll try that and post the result later today. Thanks.
    "The strength of a civilization is not measured by its ability to wage wars, but rather by its ability to prevent them." - Gene Roddenberry

  12. #12
    Join Date
    Mar 2006
    Location
    The Netherlands
    Posts
    300
    Thanks
    9
    Thanked 29 Times in 29 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11

    Default Re: QT4: Sorting in QTreeWidget (subclass)

    Yep, that was it, of course. Thanks for your help!
    "The strength of a civilization is not measured by its ability to wage wars, but rather by its ability to prevent them." - Gene Roddenberry

  13. #13
    Join Date
    Mar 2006
    Location
    The Netherlands
    Posts
    300
    Thanks
    9
    Thanked 29 Times in 29 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11

    Default Re: QT4: Sorting in QTreeWidget (subclass)

    How do I tell a row in the treewidget to redraw itself after it has been changed by a signal/slot connection?

    I can't find anything. But I must be looking in the wrong place.

    Thanks.
    "The strength of a civilization is not measured by its ability to wage wars, but rather by its ability to prevent them." - Gene Roddenberry

  14. #14
    Join Date
    Feb 2006
    Location
    Oslo, Norway
    Posts
    6,264
    Thanks
    36
    Thanked 1,519 Times in 1,389 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows Symbian S60 Maemo/MeeGo

    Default Re: QT4: Sorting in QTreeWidget (subclass)

    In what way do you change the content of that row? It should update itself.

    Of course you can force an update of a certain part of the widget/view, but I think there might be something wrong with your approach..

    The forced update would look for example something like:
    Qt Code:
    1. update(visualRect(item));
    To copy to clipboard, switch view to plain text mode 
    or
    Qt Code:
    1. setDirtyRegion(visualRect(item));
    To copy to clipboard, switch view to plain text mode 

  15. #15
    Join Date
    Mar 2006
    Location
    The Netherlands
    Posts
    300
    Thanks
    9
    Thanked 29 Times in 29 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11

    Default Re: QT4: Sorting in QTreeWidget (subclass)

    It updates itself when I call the base class setData function inside the derived setData function. If I don't, it won't. In some cases (some roles), I want to do something else with incoming data, and not call the base class function.

    I assume that the base class function calls one of those update functions (which is how it happens 'automatically'). And maybe I have to do that too.

    The update() function doesn't work.

    Just to clarify, my setData function only changes one of those four private variables. So I'm not surprised the update doesn't happen automatically.

    EDIT: I've found a solution. Not sure it's the best one. In the setData function, I call the QTreeWidgetItem::setText(int column, QString text). If there's a better way (I suspect there is a way which calls getData), please let me know.
    Last edited by Michiel; 28th March 2006 at 19:33.
    "The strength of a civilization is not measured by its ability to wage wars, but rather by its ability to prevent them." - Gene Roddenberry

  16. #16
    Join Date
    Feb 2006
    Location
    Oslo, Norway
    Posts
    6,264
    Thanks
    36
    Thanked 1,519 Times in 1,389 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows Symbian S60 Maemo/MeeGo

    Default Re: QT4: Sorting in QTreeWidget (subclass)

    Yes, the base class implementation of setData() leads the internal tree model to emit dataChanged() signal which furthermore causes the view to update itself.

  17. #17
    Join Date
    Feb 2006
    Location
    Oslo, Norway
    Posts
    6,264
    Thanks
    36
    Thanked 1,519 Times in 1,389 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows Symbian S60 Maemo/MeeGo

    Default Re: QT4: Sorting in QTreeWidget (subclass)

    Quote Originally Posted by Michiel
    In the setData function, I call the QTreeWidgetItem::setText(int column, QString text).
    QTreeWidgetItem::setText(column, text) is exactly the same than
    QTreeWidgetItem::setData(column, Qt::DisplayRole, text)

    Edit: I would suggest you to simply call the base class implementation, or what's the loss with that? You can pick your member variables and still call the base class implementation..

    Qt Code:
    1. void TreeWidgetItem::setData(int column, int role, const QVariant & value) {
    2. QTreeWidgetItem::setData(column, role, value);
    3. // pick your variables
    4. if (role == Qt::EditRole)
    5. ..
    6. else if (role == Qt::UserRole)
    7. ..
    8. }
    To copy to clipboard, switch view to plain text mode 
    Last edited by wysota; 28th March 2006 at 20:21.

  18. #18
    Join Date
    Mar 2006
    Location
    The Netherlands
    Posts
    300
    Thanks
    9
    Thanked 29 Times in 29 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11

    Default Re: QT4: Sorting in QTreeWidget (subclass)

    It might do a lot of redundant stuff. Like, set the text itself, then overwrite it again with my code.

    Also, wouldn't it update before my data is changed?
    "The strength of a civilization is not measured by its ability to wage wars, but rather by its ability to prevent them." - Gene Roddenberry

  19. #19
    Join Date
    Feb 2006
    Location
    Oslo, Norway
    Posts
    6,264
    Thanks
    36
    Thanked 1,519 Times in 1,389 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows Symbian S60 Maemo/MeeGo

    Default Re: QT4: Sorting in QTreeWidget (subclass)

    Umm..
    Quote Originally Posted by Michiel
    Just to clarify, my setData function only changes one of those four private variables.
    Well, change the order. Do your stuff first and call the base class implementation afterwards..
    You could also do a trick like when your setData() receives a QDateTime variant with user role, you pick that date as a member variable and pass QDateTime.toString() with display role to the base class implementation.

    But anyway.. don't take this as offense, but is there really any need for overriding data() and setData() at all? Unless you are gonna do some more customize stuff, you could avoid all this hassle and handle it by just simply overriding the operator used for comparing..

  20. #20
    Join Date
    Mar 2006
    Location
    The Netherlands
    Posts
    300
    Thanks
    9
    Thanked 29 Times in 29 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11

    Default Re: QT4: Sorting in QTreeWidget (subclass)

    How could I intercept a user-edit of a field otherwise? If a user changes a date with the keyboard, I'll need QDateTime::fromString() to convert it to a date. As far as I can see, overwriting setData is the only way. And since I have to use it anyway, why not put everything else relevant in there too? I need a function to change _start and _end from the outside anyway. setData seems to do the trick.

    That, and I'm just trying to program the way the qt developers probably intend me to. Since those functions are virtual, I think they should be overwritten by subclasses. I didn't know what other parts of QT relied on them.
    "The strength of a civilization is not measured by its ability to wage wars, but rather by its ability to prevent them." - Gene Roddenberry

Similar Threads

  1. Drag and Drop in a QTreeWidget subclass
    By kishore in forum Qt Programming
    Replies: 2
    Last Post: 14th May 2008, 07:12
  2. Sorting column in QTreeWidget
    By lni in forum Qt Programming
    Replies: 8
    Last Post: 14th November 2007, 18:35
  3. Sorting in QTreeWidget
    By adhit in forum Qt Programming
    Replies: 15
    Last Post: 8th May 2007, 12:49
  4. resizing a QTreeWidget
    By drhex in forum Qt Programming
    Replies: 6
    Last Post: 27th October 2006, 22:32

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.