Results 1 to 4 of 4

Thread: QFontMetrics::boundingRect() and QPainter::draw() differences.

  1. #1
    Join Date
    Jan 2006
    Location
    Germany
    Posts
    4,380
    Thanks
    19
    Thanked 1,005 Times in 913 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows Symbian S60
    Wiki edits
    5

    Default QFontMetrics::boundingRect() and QPainter::draw() differences.

    Hi,

    I made a delegate for multiline entries for QListView. The problem I am facing right now is that the sizehint method is not accurate. If you run the sample code and slowly change the width of the listview you will recognice that on specific width a "item line" is too high. (sizeHint is calculating one text line too much. QPainter on the other hand can render the text in X - 1 line.)

    Qt Code:
    1. #include <QtGui>
    2. #include <QtWidgets>
    3.  
    4. class Delegate : public QItemDelegate
    5. {
    6. Q_OBJECT
    7. public:
    8. explicit Delegate(QObject *parent = 0)
    9. : QItemDelegate(parent)
    10. , m_padding(6)
    11. {}
    12.  
    13. QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
    14. {
    15. const QFontMetrics fm = option.fontMetrics;
    16. const QString &text = index.data().toString();
    17. const QRect r = QRect(0, 0, option.rect.width() - 2 * m_padding, 0);
    18.  
    19. QSize s = option.fontMetrics.boundingRect(r, Qt::AlignLeft | Qt::TextWordWrap, text).size();
    20. s.setHeight(s.height() + 2 * m_padding);
    21. s.setWidth(s.width() + 2 * m_padding);
    22. return s;
    23. }
    24.  
    25. void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
    26. {
    27. bool selected = option.state & QStyle::State_Selected;
    28.  
    29. if (selected)
    30. painter->fillRect(option.rect, option.palette.highlight());
    31. else if (option.features & QStyleOptionViewItem::Alternate)
    32. painter->fillRect(option.rect, option.palette.alternateBase());
    33.  
    34. painter->setPen(selected
    35. ? option.palette.highlightedText().color()
    36. : option.palette.text().color());
    37.  
    38. const QRect r = option.rect.adjusted(m_padding , m_padding , -m_padding , -m_padding);
    39. painter->drawText(r, Qt::AlignLeft | Qt::TextWordWrap, index.data().toString());
    40. }
    41.  
    42. private:
    43. int m_padding;
    44. };
    45.  
    46. int main(int argc, char *argv[])
    47. {
    48. QApplication a(argc, argv);
    49.  
    50. l << "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean vel ligula tellus.";
    51. l << "Quisque lorem leo, porta in bibendum vitae, pellentesque mollis dui. Suspendisse viverra sollicitudin volutpat. Pellentesque arcu est, dignissim vel tempus at, facilisis et diam.";
    52. l << "Suspendisse est urna, feugiat vel dignissim ut, aliquet nec eros.";
    53.  
    54. QStringListModel model(l);
    55. Delegate delegate;
    56.  
    57. QListView view;
    58. view.setModel(&model);
    59. view.setItemDelegate(&delegate);
    60. view.setWordWrap(true);
    61. view.setAlternatingRowColors(true);
    62. view.show();
    63.  
    64. return a.exec();
    65. }
    66.  
    67. #include "main.moc"
    To copy to clipboard, switch view to plain text mode 

    It is because QFontMetrics::boundingRect() is returning a larger bounding box, because it uses also the maximum left and right font bearings. But how can I calculate them in sizeHint? I have tried different calculation but all failed.


    Thanks,
    Lykurg

  2. #2
    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: QFontMetrics::boundingRect() and QPainter::draw() differences.

    I had similar problems a couple of days ago. For example I noticed there is a difference in result between this call:
    Qt Code:
    1. QSize s = QFontMetrics(...).boundingRect("Some text").size();
    To copy to clipboard, switch view to plain text mode 
    and this one:
    Qt Code:
    1. QSize s = QFontMetrics(...).boundingRect(QRect(100, 100, 100, 100), 0, "Some text").size();
    To copy to clipboard, switch view to plain text mode 

    Maybe try passing the real rect the text is to occupy, e.g. option.rect.adjusted(m_padding, m_padding, -m_padding, -m_padding). Maybe you'll get better results.

    By the way, isn't the default delegate already wrapping lines in some cases?

    Another solution would be to go through QTextLayout or QStaticText.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  3. #3
    Join Date
    Jan 2006
    Location
    Germany
    Posts
    4,380
    Thanks
    19
    Thanked 1,005 Times in 913 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows Symbian S60
    Wiki edits
    5

    Default Re: QFontMetrics::boundingRect() and QPainter::draw() differences.

    Quote Originally Posted by wysota View Post
    Maybe try passing the real rect the text is to occupy, e.g. option.rect.adjusted(m_padding, m_padding, -m_padding, -m_padding). Maybe you'll get better results.

    By the way, isn't the default delegate already wrapping lines in some cases?
    Well that was my first attempt to call QItemDelegate::sizeHint and then deal with my padding. Since that failed, I continued to calculate myself... I had allready also tried to pass the real rect. Same missbehavior.

    Another solution would be to go through QTextLayout or QStaticText.
    After a quick shot with QTextLayout things get worser But that is probably because I am not familiar with QTextLayout. I'll dig deeper and see if I can manage it.

    Thanks for the tip.

  4. #4

    Default Re: QFontMetrics::boundingRect() and QPainter::draw() differences.

    I know this a super old post, but I came across the same issue and solved the issue by doing the following helper function in my subclassed QStyledItemDelegate class.

    Qt Code:
    1. QRectF rectFromText( const QModelIndex& index, QPainter* painter = nullptr ) const
    2. {
    3. QString text = index.data( Qt::UserRole + 1 ).value< QString >();
    4. QRectF font_rect;
    5.  
    6. if( painter != nullptr )
    7. {
    8. QTextOption text_options;
    9. text_options.setWrapMode( QTextOption::WrapAtWordBoundaryOrAnywhere );
    10. text_options.setAlignment( Qt::AlignLeft | Qt::AlignVCenter );
    11.  
    12. font_rect = painter->boundingRect( QRectF( 0, 0, parent_list_widget_->width() * 0.5, 10000 ), text, text_options );
    13. const_cast< QAbstractItemModel* >( index.model() )->setData( index, QVariant::fromValue( font_rect ), Qt::UserRole + 2 );
    14. }
    15. // If we don't have a QPainter, this probably means we're calling from contexts for
    16. // tooltip positioning, sizeHint, and or the click events from the parent list widget.
    17. // We're pretty much guaranteed that the paint event would've drawn it by now, before querying this,
    18. // it should always be populated by here.
    19. else
    20. {
    21. font_rect = index.data( Qt::UserRole + 2 ).value< QRectF >();
    22. }
    23.  
    24. return font_rect;
    25. }
    To copy to clipboard, switch view to plain text mode 

    This gave the ability for the painter and any other function to retrieve what the painted size would be and it worked for QAbstractItemDelegate::helpEvent, QAbstractItemDelegate:aint, QAbstractItemDelegate::sizeHint, and even outside contexts of the delegate, like click events from the perspective of a parental QListWidget. I used this to make a chat widget, so sender and receiver would have their bounding rectangles positions relative to left or right aligned sides depending on who was the sender. I only wanted click events to be within the area for that item rather than the entire row, like it normally would. Hopefully this helps someone, because I wish I had this knowledge before delving down the rabbit hole.

Similar Threads

  1. A crash in QFontMetrics::boundingRect()
    By npirocanac in forum Qt for Embedded and Mobile
    Replies: 1
    Last Post: 5th February 2013, 12:47
  2. How does one draw a 'cut down' ellipse using QPainter
    By Eos Pengwern in forum Qt Programming
    Replies: 3
    Last Post: 24th July 2012, 02:01
  3. How to specify QRect argument to QFontMetrics::boundingRect()
    By John Mcgehee in forum Qt Programming
    Replies: 0
    Last Post: 13th October 2010, 05:50
  4. Replies: 5
    Last Post: 15th January 2009, 10:03
  5. Replies: 3
    Last Post: 30th April 2006, 20:22

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.