Results 1 to 18 of 18

Thread: QListView word wrap

  1. #1
    Join Date
    May 2007
    Posts
    10
    Thanks
    1
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11

    Red face QListView word wrap

    Hi All,
    my first on this forum is regarding QListView.
    I have strings of arbitrary length in my model and I want them to wrap in a QListView when the length of the string is longer than the width of the QListView.
    QListView::setWordWrap(true) method does not seem to do anything at all.
    I created a custom QItemDelegate and reimplemented sizeHint(). I had to make QListView a parent of QItemDelegate, so I can get a width of the QListView.
    It did help though. When I drag a border of QListView and make the width smaller, the height of the item increases, based on sizeHint() and the string automatically wraps to the next line. Now when I drag a border of QListView to the other side and increase the width, the strings unwrap, but the height of the item stay the same, leaving empty space. The height of the item area only grows, but never gets smaller despite of the returning value of sizeHint().

    Is the any way to fix this behaviour?

    serega.

  2. #2
    Join Date
    Feb 2006
    Location
    Romania
    Posts
    2,744
    Thanks
    8
    Thanked 541 Times in 521 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QListView word wrap

    Of course it is.
    Could we see your implementation of sizeHint?

  3. #3
    Join Date
    May 2007
    Posts
    10
    Thanks
    1
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11

    Default Re: QListView word wrap

    Here it is:
    Qt Code:
    1. QSize PartOfSpeechItemDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const
    2. {
    3. QAbstractItemView *view = dynamic_cast<QAbstractItemView*>(parent());
    4. QFontMetrics fontMetrics = view->fontMetrics();
    5. QRect rect = fontMetrics.boundingRect(index.data().toString());
    6. int proportion = (rect.width() / (view->width() + 4));
    7. if (proportion == 0 || rect.width() > view->width())
    8. proportion++;
    9.  
    10. return QSize(view->width() - 4, rect.height() * proportion);
    11. }
    To copy to clipboard, switch view to plain text mode 

    serega.
    Last edited by jacek; 5th August 2007 at 00:42. Reason: changed [html] to [code]

  4. #4
    Join Date
    Feb 2006
    Location
    Romania
    Posts
    2,744
    Thanks
    8
    Thanked 541 Times in 521 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QListView word wrap

    The code seems OK.
    Have you tried setting the list view's resize mode to QListView::Adjust, with setResizeMode?

    This causes the items to be laid out again at resize.
    You might be experiencing this due to items position/size caching.

    Regards

  5. #5
    Join Date
    May 2007
    Posts
    10
    Thanks
    1
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11

    Default Re: QListView word wrap

    I already had resizeMode set to Adjust.

    I also noticed that it works when there is enough items for a vertical scrollbar.

    But when the QListView is not fully filled, and does not show the scrollbar the height of individual items only grows when QListView gets squeezed. Enlarging QListView does not change the height of items.

    serega.

  6. #6
    Join Date
    Feb 2006
    Location
    Romania
    Posts
    2,744
    Thanks
    8
    Thanked 541 Times in 521 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QListView word wrap

    What if you override the paint() for QItemDelegate too?
    Then you have complete control in this aspect.
    Shouldn't be that hard, because you're drawing only text, after all.

    Regards

  7. #7
    Join Date
    May 2007
    Posts
    10
    Thanks
    1
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11

    Default Re: QListView word wrap

    Yes, I will try that. But I am wondering..., I can paint on the area specified by the QStyleOptionViewItem.rect property, which I cannot control directly. I can only provide sizeHint().


    serega.

  8. #8
    Join Date
    Feb 2006
    Location
    Romania
    Posts
    2,744
    Thanks
    8
    Thanked 541 Times in 521 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QListView word wrap

    sizeHint means the size the item prefers to have.
    There is no guarantee that it will have that size - but most of the times will.

    The style option rect will be identical with the sizeHint, as it represents the current size of the item.

    Regards

  9. #9
    Join Date
    May 2007
    Posts
    10
    Thanks
    1
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11

    Default Re: QListView word wrap

    [QUOTE=marcel;39019]sizeHint means the size the item prefers to have.
    There is no guarantee that it will have that size - but most of the times will.
    [/QUOTE/
    That is the problem, there is no quarantee.
    The style option rect will be identical with the sizeHint, as it represents the current size of the item.
    I verified and that is true, but the area that QListView allocates for items does not always match the sizeHint(). As you pointed out before there is probably some caching going on. May be I can subclass QListView and do something there...

    serega.

  10. #10
    Join Date
    May 2007
    Posts
    10
    Thanks
    1
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11

    Default Re: QListView word wrap

    I subclassed QListView and reimplemented resizeEvent().
    I simply call reset() when new width is greater than the old width of the QListView.
    It seems to be a brute solution, but it fixed the problem.

    serega.

  11. #11
    Join Date
    Aug 2007
    Posts
    244
    Thanks
    42
    Thanked 8 Times in 8 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: QListView word wrap

    Quote Originally Posted by serega View Post
    Here it is:
    [HTML]
    QSize PartOfSpeechItemDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const
    {
    QAbstractItemView *view = dynamic_cast<QAbstractItemView*>(parent());
    QFontMetrics fontMetrics = view->fontMetrics();
    QRect rect = fontMetrics.boundingRect(index.data().toString());
    int proportion = (rect.width() / (view->width() + 4));
    if (proportion == 0 || rect.width() > view->width())
    proportion++;

    return QSize(view->width() - 4, rect.height() * proportion);
    }
    [/HTML]

    serega.
    what is the parent() function on line 3 in the above code? Maybe an error?

    Thanks
    Giuseppe CalÃ

  12. #12
    Join Date
    Feb 2006
    Location
    Romania
    Posts
    2,744
    Thanks
    8
    Thanked 541 Times in 521 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QListView word wrap

    It is the parent list view.
    When you set the delegate with QAbstractItemView::setItemDelegate, the view takes ownership of the delegate and reparents it.

    What you see in that code is actually QObject:arent().

    Regards

  13. #13
    Join Date
    Aug 2007
    Posts
    244
    Thanks
    42
    Thanked 8 Times in 8 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: QListView word wrap

    Is this equivalent?

    Qt Code:
    1. QSize PartOfSpeechItemDelegate::sizeHint(QWidget *parent, const QStyleOptionViewItem& option, const QModelIndex& index) const
    2. {
    3. QAbstractItemView *view = dynamic_cast<QAbstractItemView*>(parent);
    4. QFontMetrics fontMetrics = view->fontMetrics();
    5. QRect rect = fontMetrics.boundingRect(index.data().toString());
    6. int proportion = (rect.width() / (view->width() + 4));
    7. if (proportion == 0 || rect.width() > view->width())
    8. proportion++;
    9.  
    10. return QSize(view->width() - 4, rect.height() * proportion);
    11. }
    To copy to clipboard, switch view to plain text mode 
    Giuseppe CalÃ

  14. #14
    Join Date
    Feb 2006
    Location
    Romania
    Posts
    2,744
    Thanks
    8
    Thanked 541 Times in 521 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QListView word wrap

    Is PartOfSpeechItem delegate a QAbstractItemDelegate?
    Because the signature of QAbstractItemDelegate::sizeHint differs from your implementation. It does not have a QWidget* parameter.


    Regards

  15. #15
    Join Date
    Aug 2007
    Posts
    244
    Thanks
    42
    Thanked 8 Times in 8 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: QListView word wrap

    I was trying using this sizeHint() code to solve my problem. Using this code like it is give me an error (‘parent’ was not declared in this scope) while changing the signature like in my previous post, program compile without error, even if it doesn't solve the problem.

    Bye
    Giuseppe CalÃ

  16. #16
    Join Date
    Feb 2006
    Location
    Romania
    Posts
    2,744
    Thanks
    8
    Thanked 541 Times in 521 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QListView word wrap

    Well, I don't know if it is a typo, but in your code should be parent() not parent.
    You must call the function. There is not parent object.

    Regards

  17. #17
    Join Date
    Aug 2007
    Posts
    244
    Thanks
    42
    Thanked 8 Times in 8 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: QListView word wrap

    Sorry marcel if i ask you in this manner, but can you review the sizeHint() in this post and explain me a way for changing row height if text wraps ? (with that code the rows height are always one line independently if text wraps, and the wrapped text overlaps the rows below).

    Regards
    Giuseppe CalÃ

  18. #18
    Join Date
    May 2007
    Posts
    10
    Thanks
    1
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11

    Default Re: QListView word wrap

    I haven't played with my application for a while, now I came back to it and to sizeHint(). Below is my current implementation, which provides may be not perfect, but very good results.
    There was some questions above regarding parent(). Ideally QAbstractItemDelegate do not need to know about QAbstractItemView, but in my case I have to set the view as a parent of the delegate because I need the width of the view to determine the height.
    Qt Code:
    1. QSize PartOfSpeechItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
    2. {
    3. QAbstractItemView *view = dynamic_cast<QAbstractItemView*>(parent());
    4. QFontMetricsF fontMetrics(view->fontMetrics());
    5. QString str = index.data().toString().trimmed();
    6. QStringList words = str.split(QChar(' '));
    7. QRectF boundingRect = fontMetrics.boundingRect(str);
    8. int width = view->viewport()->width() - 6;
    9. int times = 0;
    10. while (words.size() > 0) {
    11. times++;
    12. qreal lineWidth = 0;
    13. bool enoughSpace = true;
    14. do {
    15. QString word = words.first();
    16. qreal wordWidth = fontMetrics.width(word);
    17. if (wordWidth + lineWidth < width) {
    18. lineWidth += wordWidth;
    19. lineWidth += fontMetrics.width(QChar(' '));
    20. words.removeFirst();
    21. } else
    22. enoughSpace = false;
    23.  
    24. } while (enoughSpace && words.size() > 0);
    25. }
    26. return QSize(width, boundingRect.height() * times - times + 1);
    27. }
    28.  
    29. void PartOfSpeechItemDelegate::paint(QPainter *painter,
    30. const QStyleOptionViewItem &option, const QModelIndex &index) const
    31. {
    32. QRect rect(option.rect.topLeft(), option.rect.bottomRight());
    33. if (option.state & QStyle::State_Selected)
    34. painter->fillRect(rect, option.palette.highlight());
    35.  
    36. painter->save();
    37. painter->setPen(QPen(Qt::gray));
    38. painter->drawLine(rect.topLeft(), rect.topRight());
    39. painter->restore();
    40.  
    41. rect.setLeft(rect.left() + 4);
    42. rect.setTop(rect.top() + 2);
    43. rect.setRight(rect.right() - 2);
    44. painter->drawText(rect, Qt::TextWordWrap , index.data().toString());
    45. }
    To copy to clipboard, switch view to plain text mode 

    My view:
    Qt Code:
    1. void PartOfSpeechItemView::resizeEvent(QResizeEvent *resizeEvent)
    2. {
    3. reset();
    4. QListView::resizeEvent(resizeEvent);
    5. }
    To copy to clipboard, switch view to plain text mode 

    See the attachment how it looks like.

    serega.
    Attached Images Attached Images

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.