Lykurg
27th February 2013, 10:02
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.)
#include <QtGui>
#include <QtWidgets>
class Delegate : public QItemDelegate
{
Q_OBJECT
public:
explicit Delegate(QObject *parent = 0)
: QItemDelegate(parent)
, m_padding(6)
{}
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
const QFontMetrics fm = option.fontMetrics;
const QString &text = index.data().toString();
const QRect r = QRect(0, 0, option.rect.width() - 2 * m_padding, 0);
QSize s = option.fontMetrics.boundingRect(r, Qt::AlignLeft | Qt::TextWordWrap, text).size();
s.setHeight(s.height() + 2 * m_padding);
s.setWidth(s.width() + 2 * m_padding);
return s;
}
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
bool selected = option.state & QStyle::State_Selected;
if (selected)
painter->fillRect(option.rect, option.palette.highlight());
else if (option.features & QStyleOptionViewItem::Alternate)
painter->fillRect(option.rect, option.palette.alternateBase());
painter->setPen(selected
? option.palette.highlightedText().color()
: option.palette.text().color());
const QRect r = option.rect.adjusted(m_padding , m_padding , -m_padding , -m_padding);
painter->drawText(r, Qt::AlignLeft | Qt::TextWordWrap, index.data().toString());
}
private:
int m_padding;
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QStringList l;
l << "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean vel ligula tellus.";
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.";
l << "Suspendisse est urna, feugiat vel dignissim ut, aliquet nec eros.";
QStringListModel model(l);
Delegate delegate;
QListView view;
view.setModel(&model);
view.setItemDelegate(&delegate);
view.setWordWrap(true);
view.setAlternatingRowColors(true);
view.show();
return a.exec();
}
#include "main.moc"
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
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.)
#include <QtGui>
#include <QtWidgets>
class Delegate : public QItemDelegate
{
Q_OBJECT
public:
explicit Delegate(QObject *parent = 0)
: QItemDelegate(parent)
, m_padding(6)
{}
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
const QFontMetrics fm = option.fontMetrics;
const QString &text = index.data().toString();
const QRect r = QRect(0, 0, option.rect.width() - 2 * m_padding, 0);
QSize s = option.fontMetrics.boundingRect(r, Qt::AlignLeft | Qt::TextWordWrap, text).size();
s.setHeight(s.height() + 2 * m_padding);
s.setWidth(s.width() + 2 * m_padding);
return s;
}
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
bool selected = option.state & QStyle::State_Selected;
if (selected)
painter->fillRect(option.rect, option.palette.highlight());
else if (option.features & QStyleOptionViewItem::Alternate)
painter->fillRect(option.rect, option.palette.alternateBase());
painter->setPen(selected
? option.palette.highlightedText().color()
: option.palette.text().color());
const QRect r = option.rect.adjusted(m_padding , m_padding , -m_padding , -m_padding);
painter->drawText(r, Qt::AlignLeft | Qt::TextWordWrap, index.data().toString());
}
private:
int m_padding;
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QStringList l;
l << "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean vel ligula tellus.";
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.";
l << "Suspendisse est urna, feugiat vel dignissim ut, aliquet nec eros.";
QStringListModel model(l);
Delegate delegate;
QListView view;
view.setModel(&model);
view.setItemDelegate(&delegate);
view.setWordWrap(true);
view.setAlternatingRowColors(true);
view.show();
return a.exec();
}
#include "main.moc"
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