PDA

View Full Version : QPainter::drawText() with word wrap



zgulser
17th December 2013, 15:47
Hi,

I have QListView which I display my item's(in the model) specific data on it. If the item's message data is too long I need to resize the drawText rectangle in order to fit the string to the given option rect. I looked at the forum and find some useful code but still having no success. I have still the following case;

9863

It seems like I couldn't get the text wrapped inside drawText method. Here is my delegate class code. Any help will be greatly appreciated.


void ChatViewListItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QRect rect = option.rect;
int textOffset = 5;
QPalette pal = option.palette;
QVariant variant = index.data(Qt::UserRole);

painter->save();

QString displayName;
QDateTime dateTime;
QString dateTimeInString;
QString messageContent;
QString direction;
QString state;

if(variant.canConvert<ChatMessageHistoryItem>())
{
ChatMessageHistoryItem item = variant.value<ChatMessageHistoryItem>();
displayName = ApplicationManager::getInstance()->getAddressBookManager()->findContactName((item.getDisplayName()));
dateTime = item.getDateTime();
dateTimeInString = dateTime.toString("dd/MM/yyyy hh:mm");
direction = item.getDirection();
state = item.getState();
messageContent = qvariant_cast<QString>(index.data(ChatViewListModel::MessageContentRole) );

if(item.getDirection().compare(HistoryItem::DIRECT ION_INCOMING) == 0)
{
painter->setPen(QColor("#034567"));
}
else
{
if(ApplicationManager::getInstance()->getAddressBookManager()->getMyContact())
{
displayName = ApplicationManager::getInstance()->getAddressBookManager()->getMyContact()->getDisplayName();
}
painter->setPen(QColor("#B0171F"));
//painter->setPen(QColor("#034567"));
}
}

/*
if(!direction.isNull() &&
!direction.isEmpty() &&
direction.compare(HistoryItem::DIRECTION_OUTGOING) == 0)
{
painter->fillRect(option.rect, QColor("#F5F7FA"));
}
*/

QFont defaultFont = QApplication::font();
QFont nameFont(defaultFont);
nameFont.setPixelSize(12);
nameFont.setBold(true);
QFontMetrics nameFontFontMetrics(nameFont);
int textHeightInPixels = nameFontFontMetrics.height();

QFont dateTimeFont = QApplication::font();
dateTimeFont.setPixelSize(9);
QFontMetrics dateTimeFontMetrics(dateTimeFont);
int dateTimeTextWidthInPixels = dateTimeFontMetrics.width(dateTimeInString);

QRect displayNameRect = nameFontFontMetrics.boundingRect(textOffset,
rect.top() + 5,
rect.width() - textOffset - dateTimeTextWidthInPixels - 5 - 10 , 0,
Qt::AlignLeft|Qt::AlignTop|Qt::TextWordWrap,
displayName);
painter->setFont(nameFont);
painter->drawText(displayNameRect, Qt::AlignLeft|Qt::AlignTop|Qt::TextWordWrap, displayName);

painter->setFont(dateTimeFont);
painter->setPen(QColor(Qt::lightGray));
painter->drawText(rect.x() + rect.width() - dateTimeTextWidthInPixels - 5, rect.y() + 15, dateTimeInString);

QFont messageFont = QApplication::font();
messageFont.setPixelSize(11);
QFontMetrics messageFontMetrics(messageContent);
int messageTextHeightInPixels = messageFontMetrics.height();

QRect messageContentRect = messageFontMetrics.boundingRect(textOffset,
rect.top() + textHeightInPixels + 8,
rect.width() - textOffset - dateTimeTextWidthInPixels - 5 - 10 , 0,
Qt::AlignLeft|Qt::AlignTop|Qt::TextWordWrap,
messageContent);
painter->setFont(messageFont);
painter->setPen(QColor("#363636"));
painter->drawText(messageContentRect, Qt::AlignLeft|Qt::AlignTop|Qt::TextWordWrap, messageContent);

QIcon icon = qvariant_cast<QIcon>(index.data(Qt::DecorationRole));
QPixmap pixmapDeliveryStatus = icon.pixmap(12, 12);

if(!direction.isNull() &&
!direction.isEmpty() &&
direction.compare(HistoryItem::DIRECTION_OUTGOING) == 0)
{
if(state.compare(HistoryItem::STATE_SENT, Qt::CaseInsensitive) == 0)
{
pixmapDeliveryStatus = icon.pixmap(14, 14);
}

painter->drawPixmap(rect.x() +rect.width() - pixmapDeliveryStatus.width() - 5, rect.y() + textHeightInPixels + 8 , pixmapDeliveryStatus);

if(state.compare(HistoryItem::STATE_DISPLAYED, Qt::CaseInsensitive) == 0)
{
painter->drawPixmap(rect.x() +rect.width() - pixmapDeliveryStatus.width() - 9, rect.y() + textHeightInPixels + 8 , pixmapDeliveryStatus);
}
}

painter->setPen(QColor("#E5E5E5"));
painter->drawLine(textOffset, rect.y() + textHeightInPixels + messageTextHeightInPixels + 10, rect.width() - textOffset, rect.y() + textHeightInPixels + messageTextHeightInPixels + 10);

painter->restore();
}

QSize ChatViewListItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
int textOffset = 5;
QRect rect = option.rect;
QVariant variant = index.data(Qt::UserRole);
QString displayName = "";
QString messageContent = "";
QString dateTimeInString = "";
if(variant.canConvert<ChatMessageHistoryItem>())
{
ChatMessageHistoryItem item = variant.value<ChatMessageHistoryItem>();
displayName = ApplicationManager::getInstance()->getAddressBookManager()->findContactName((item.getDisplayName()));
dateTimeInString = item.getDateTime().toString("dd/MM/yyyy hh:mm");
messageContent = qvariant_cast<QString>(index.data(ChatViewListModel::MessageContentRole) );
}

QFont dateTimeFont = QApplication::font();
dateTimeFont.setPixelSize(9);
QFontMetrics dateTimeFontMetrics(dateTimeFont);
int dateTimeTextWidthInPixels = dateTimeFontMetrics.width(dateTimeInString);

QFont defaultFont = QApplication::font();
QFont nameFont(defaultFont);
nameFont.setPixelSize(12);
nameFont.setBold(true);
QFontMetrics nameFontFontMetrics(nameFont);
int textHeightInPixels = nameFontFontMetrics.height();

int value = rect.width() - textOffset - dateTimeTextWidthInPixels - 5 - 10;

QRect displayNameRect = nameFontFontMetrics.boundingRect(0, 0,
rect.width() - textOffset - dateTimeTextWidthInPixels - 5 - 10, 0,
Qt::AlignLeft|Qt::AlignTop|Qt::TextWordWrap,
displayName);

QFont messageFont = QApplication::font();
messageFont.setPixelSize(11);
QFontMetrics messageFontMetrics(messageContent);
int messageTextHeightInPixels = messageFontMetrics.height();

QRect messageContentRect = messageFontMetrics.boundingRect(0, 0,
rect.width() - textOffset - dateTimeTextWidthInPixels - 5 - 10 , 0,
Qt::AlignLeft|Qt::AlignTop|Qt::TextWordWrap,
messageContent);

QSize sizeAdjusted(option.rect.width(), displayNameRect.height() + messageContentRect.height());

qDebug() << "total height: " << displayNameRect.height() + messageContentRect.height();
// Keep the minimum height needed in mind.
if(sizeAdjusted.height() < ITEM_HEIGHT)
{
sizeAdjusted.setHeight(ITEM_HEIGHT);
}

//QSize orig = QItemDelegate::sizeHint(option, index);
//return QSize(orig.width(), ITEM_HEIGHT);
return sizeAdjusted;
}

anda_skoa
17th December 2013, 18:30
From your screen shot it looks like you have a very long word, so word wrap can't break it.

Have you tried Qt::TextWrapAnywhere?

Cheers,
_

zgulser
18th December 2013, 09:10
Yeah, just tried and it worked. Thanks for your advice.

Now I'm facing a bit minor problem. Text is wrapped as expected but returned size's height is much bigger than the text wrapped. See the attached view. Any ideas for that?

9865

anda_skoa
18th December 2013, 09:47
The screenshot is extremely small, but I assume you mean that the item height is taller than what you expect.

One thing you can try is to get the actually consumed bounding rect for the text drawing. The drawText() method has an option QRect pointer argument that, if present, will be set to the bounding rect the text actually needed when drawn.



QRect usedRect;
painter->drawText( itemRect, flags, text, &usedRect );


Cheers,
_

zgulser
18th December 2013, 11:30
Hi,

I didn't recognize the parameter that you suggest. I tried it but no luck. Thanks anyways.

Added after 12 minutes:

Oh I caught the error. I set message instead of font in the sizeHint(...). Problem solved.