How to calculate line while wrapping text in QLIstview
-
Hi,
I am working on messaging application. I have a delegate which arrange text in different rect to draw text. I have to show - Name, date and time, Subject, Message , message status Icon. It doesnt work well (ie it create extra lines) in case if word is long . There is some problem in calculating in sizeHint but i tried different scenarios and couldnt make it working . for long text there are always extra lines coming in QLIstView .
Please check the link below :
!http://tinypic.com/r/34dt1de/5(Message shown in QListView)!Here's the code for this:
@
QSize ConversationViewItemDelegate::sizeHint(const QStyleOptionViewItem& , const QModelIndex& index) const
{
QString str = index.data().toString();QListView *view = (QListView*)parent(); QFontMetrics fontMetrics(view->font()); QStringList words = str.split(QChar(' ')); words.removeAll("\n"); QStringList lines = str.split(QChar('\n')); int noOfLines = lines.size(); QRectF boundingRect = fontMetrics.boundingRect(str); int width = view->viewport()->width() -35; int height = boundingRect.height(); int times = 0; while (words.size() > 0) { times++; qreal lineWidth = 0; bool enoughSpace = true; do { QString word = words.first(); qreal wordWidth = fontMetrics.width(word); wordWidth = wordWidth + lineWidth; lineWidth = 0; if(wordWidth > width) { times++; while(wordWidth > width ) { times++; wordWidth -= width; } lineWidth += wordWidth; lineWidth += fontMetrics.width(QChar(' ')); words.removeFirst(); } else if (wordWidth < width) { lineWidth += wordWidth; lineWidth += fontMetrics.width(QChar(' ')); words.removeFirst(); } else enoughSpace = false; } while (enoughSpace && words.size() > 0); } height = height * times + (noOfLines + 3)* boundingRect.height() - times; QSize sizeOfSubjectField = QSize(); if (!index.model()->data(index, ConversationViewMsgSubjectRole).toString().isEmpty()) { QString subject = "Subject: " + index.model()->data(index, ConversationViewMsgSubjectRole).toString(); sizeHintforSubject(subject); } else { height = height - boundingRect.height(); } height += sizeOfSubjectField.height(); return QSize(width, height);
}
QSize ConversationViewItemDelegate::sizeHintforSubject(QString str) const
{
QListView p = (QListView)parent();
QString text = str;
QFontMetrics fm(p->font());float rw = float(p->viewport()->size().width()); float tw = fm.width(text); float ratio = tw/rw; int lines = int(ratio) + 1; return QSize(rw,lines*fm.height());
}
@
-
the paint function code is as follows:
@void ConversationViewItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex & index) const
{QString displayName = index.model()->data(index, ConversationViewDisplayNameRole).toString(); QString dateTime = index.model()->data(index, ConversationViewDateTimeRole).toString(); bool messageStatus = index.model()->data(index, ConversationViewMsgReadRole).toBool(); QString textMessage = index.model()->data(index, ConversationViewMessageRole).toString(); QString subject = QString(); if (!index.model()->data(index, ConversationViewMsgSubjectRole).toString().isEmpty()) { subject = "Subject: " + index.model()->data(index, ConversationViewMsgSubjectRole).toString(); } QIcon messageStatusIcon = index.model()->data(index, ConversationViewMsgStatusIcon).value<QIcon>(); QPixmap pMessageStatusPixmap = messageStatusIcon.pixmap(option.decorationSize); QRect messageRect = option.rect; QRect dateTimeRect = option.rect; QRect boundaryRect = option.rect; QRect displayNameRect = option.rect; QRect sendMessageIconRect = option.rect; QRect subjectRect = option.rect; dateTimeRect.setTop(dateTimeRect.top()+5); dateTimeRect.setBottom(dateTimeRect.top()+15); dateTimeRect.setLeft(dateTimeRect.right()- 110); dateTimeRect.setRight(dateTimeRect.right()-5); displayNameRect.setTop(displayNameRect.top()+5); displayNameRect.setBottom(displayNameRect.top()+15); displayNameRect.setLeft(displayNameRect.left()+5); displayNameRect.setRight(displayNameRect.right()-120); boundaryRect.setRight(boundaryRect.right() - 2); boundaryRect.setLeft(boundaryRect.left() + 2); if(!index.model()->data(index, ConversationViewMsgSubjectRole).toString().isEmpty()) { QSize a = sizeHintforSubject(subject); subjectRect.setTop(dateTimeRect.bottom() + 2); subjectRect.setLeft(subjectRect.left() + 10); subjectRect.setRight(subjectRect.right() - 35); subjectRect.setBottom(subjectRect.top() + a.height()); messageRect.setTop(subjectRect.bottom()+ 5); messageRect.setRight(messageRect.right() - 5); } else { messageRect.setTop(dateTimeRect.bottom()+10); messageRect.setRight(messageRect.right() - 25); } messageRect.setLeft(messageRect.left() + 10); messageRect.setBottom(messageRect.bottom() - 5); sendMessageIconRect.setTop(dateTimeRect.bottom()+2 ); sendMessageIconRect.setRight(sendMessageIconRect.right()-5); sendMessageIconRect.setLeft(sendMessageIconRect.right()- 20); sendMessageIconRect.setBottom(dateTimeRect.bottom()+20); QFont boldFont = QApplication::font(); boldFont.setBold(true); QFont normalFont = QApplication::font(); QFont italicFont = QApplication::font(); italicFont.setItalic(true); //Change color in message is UNREAD if(!messageStatus) { painter->fillRect(boundaryRect, "#C0C0C0"); } //Set selected Message item color if (option.state & QStyle::State_Selected) painter->fillRect(boundaryRect, "#C8E0FD"); painter->save(); painter->drawRoundedRect(boundaryRect, 3, 3); painter->drawText(dateTimeRect, Qt::AlignLeft , dateTime); painter->drawPixmap(sendMessageIconRect, pMessageStatusPixmap); QTextOption opt ; opt.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); painter->drawText(messageRect,textMessage, opt ); painter->setFont(italicFont); painter->drawText(subjectRect,subject, opt ); painter->setFont(boldFont); painter->drawText(displayNameRect, Qt::AlignLeft , displayName); painter->restore();
}@
some how the pic didnt come . the link for it is http://tinypic.com/r/34dt1de/5
-
Any suggestions ????
-
what is exactly the problem?!
the image you've posted seems ok? -
Hi Raven,
Thanks for the reply. Actually I am trying to make a chat view using QLIstview to show previous msges. The problem which i am facing is that where the text is very long there are extra space (extra number of lines from size hint) in list view item. i checked the previous post and wrote the size hint , it works only for small texts. If i show long text having long words then extra spaces comes in list view item. I am using WrapAtWordBoundaryOrAnywhere .
Regards,
Prankur -
maybe your text contains "\n" which cause the extra line breaks?