[Qt-interest] delegate and multi line text
david.jobet at free.fr
david.jobet at free.fr
Sat Oct 17 03:53:24 CEST 2009
Hello,
I'm trying to implement a delegate used in a QTableView to display a multi-line text.
I've been trying 2 things :
- reimplement sizeHint() and paint() myself
- use QStyle::sizeFromContents() and QStyle::drawControl() to reimplement them
First solution works and do what I want, but the multiline text feels weird because interline alignment and margins are not respected.
Second solution does not work at all for me. Looking at Qt's source code, it seems like Qt will not obey my line breaks and will wrap the text at words boundary. As a result, I see some funny characters where my '\t' and my '\n' are supposed to be and the result is not readable at all.
So here's my question : how do you paint text containing multiple lines in a delegate so that it feels 'native' ?
Tx for any help
David
solution 1 : (solution 2 follows)
QSize PatchContentDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
const UstensilePatchInfo &patch = ustensilePatchView_.get_patch(index);
QStyleOptionViewItemV4 opt = option;
initStyleOption(&opt, index);
QFontMetrics metrics(opt.font);
int width = 0;
int height = 0;
std::vector<std::string> segments;
boost::algorithm::split(segments, patch.message, boost::is_any_of("\n"));
for (std::vector<std::string>::const_iterator it = segments.begin(); it != segments.end(); ++it)
{
QRect rect = metrics.boundingRect(it->c_str());
width = std::max(width, rect.width());
height += rect.height();
}
for (size_t i = 0; i < patch.files.size(); ++i)
{
std::string entry;
switch (patch.states[i])
{
case FileState::Added :
entry = "\t\t\tAdded ";
break;
case FileState::Modified :
entry = "\t\t\tModified ";
break;
case FileState::Removed :
entry = "\t\t\tRemoved ";
break;
default :
assert(false);
break;
}
entry += patch.files[i];
QRect rect = metrics.boundingRect(entry.c_str());
width = std::max(width, rect.width());
height += rect.height();
}
return QSize(std::min(500, width), height);
}
void PatchContentDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
const UstensilePatchInfo &patch = ustensilePatchView_.get_patch(index);
QStyle &style = *QApplication::style();
painter->save();
QStyleOptionViewItemV4 opt = option;
initStyleOption(&opt, index);
style.drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter, 0);
QRect textRect = style.subElementRect(QStyle::SE_ItemViewItemText, &opt, 0);
// following code borrowed from qcommonstyle.cpp
QPalette::ColorGroup cg = opt.state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled;
if (cg == QPalette::Normal && !(opt.state & QStyle::State_Active))
{
cg = QPalette::Inactive;
}
if (opt.state & QStyle::State_Selected)
{
painter->setPen(QPen(opt.palette.brush(cg, QPalette::HighlightedText), 0));
}
else
{
painter->setPen(QPen(opt.palette.brush(cg, QPalette::Text), 0));
}
if (opt.state & QStyle::State_Editing)
{
painter->setPen(QPen(opt.palette.brush(cg, QPalette::Text), 0));
painter->drawRect(textRect.adjusted(0, 0, -1, -1));
}
QFontMetrics metrics(opt.font);
int height = 0;
std::vector<std::string> segments;
boost::algorithm::split(segments, patch.message, boost::is_any_of("\n"));
for (std::vector<std::string>::const_iterator it = segments.begin(); it != segments.end(); ++it)
{
textRect.setTop(textRect.top() + height);
style.drawItemText(painter, textRect, Qt::AlignLeft, opt.palette, true, it->c_str());
QRect bRect = metrics.boundingRect(it->c_str());
height = bRect.height();
}
for (size_t i = 0; i < patch.files.size(); ++i)
{
std::string entry;
switch (patch.states[i])
{
case FileState::Added :
entry = "\t\t\tAdded ";
break;
case FileState::Modified :
entry = "\t\t\tModified ";
break;
case FileState::Removed :
entry = "\t\t\tRemoved ";
break;
default :
assert(false);
break;
}
entry += patch.files[i];
textRect.setTop(textRect.top() + height);
style.drawItemText(painter, textRect, Qt::AlignLeft, opt.palette, true, entry.c_str());
QRect bRect = metrics.boundingRect(entry.c_str());
height = bRect.height();
}
painter->restore();
}
===========================
solution 2
QSize PatchContentDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
const UstensilePatchInfo &patch = ustensilePatchView_.get_patch(index);
QStyle &style = *QApplication::style();
QStyleOptionViewItemV4 opt = option;
initStyleOption(&opt, index);
QString text = patch.message.c_str();
for (size_t i = 0; i < patch.files.size(); ++i)
{
text += "\n";
switch (patch.states[i])
{
case FileState::Added :
text += "\t\t\tAdded ";
break;
case FileState::Modified :
text += "\t\t\tModified ";
break;
case FileState::Removed :
text += "\t\t\tRemoved ";
break;
default :
assert(false);
break;
}
text += patch.files[i].c_str();
}
opt.text = text;
QSize qts = style.sizeFromContents(QStyle::CT_ItemViewItem, &opt, QSize(), 0);
return qts.boundedTo(QSize(500, qts.height()));
}
void PatchContentDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
const UstensilePatchInfo &patch = ustensilePatchView_.get_patch(index);
QStyle &style = *QApplication::style();
QStyleOptionViewItemV4 opt = option;
initStyleOption(&opt, index);
QString text = patch.message.c_str();
for (size_t i = 0; i < patch.files.size(); ++i)
{
text += '\n';
switch (patch.states[i])
{
case FileState::Added :
text += "\t\t\tAdded ";
break;
case FileState::Modified :
text += "\t\t\tModified ";
break;
case FileState::Removed :
text += "\t\t\tRemoved ";
break;
default :
assert(false);
break;
}
text += patch.files[i].c_str();
}
opt.text = text;
style.drawControl(QStyle::CE_ItemViewItem, &opt, painter, 0);
}
More information about the Qt-interest-old
mailing list