PDA

View Full Version : QStyledItemDelegate - draw an items with a different size text and heights



migel
27th December 2011, 19:47
I have a QListView with items containing a text. Each text has different length. So I need to draw an item with different height and use word wrap.

This is perfect example how this must work.

http://www.qtcentre.org/wiki/index.php?title=Expanding_list

But this replace other longest text on click. I wanted to get rid of that code which is resp for click and update. But it just does not work then.

So question how to do it right. How to calculate a width/height of the coil and the draw a text there word wrapping ?

Thanks

migel
27th December 2011, 23:28
Some reason option.rect.width() returns 0 in QSize StatusWidgetDelegate::sizeHint()

Seems in paint() width is set fine. So I am potentially able to draw it correctly but I cannot set correct size of the item.

Added after 22 minutes:

So this is what I came up with and works how I want. But some reason I have to set


item->setSizeHint(QSize(this->width(), 10));

during insert an item to give a width for &options in QSize StatusWidgetDelegate::sizeHint(). Well, this is fine for me, but I don't like any fake information like a height = 10 ( this could be whatever value because its quickly overwritten by sizeHint() logic). Also in this example I need to use resizeEvent() to update the width of the all items. This would be not needed if &option in sizeHint() would return correct rect.

So what I am doing wrong ?

QListView


void List::insert(Status &status)
{
int row = model()->rowCount();

QStandardItem *item = new QStandardItem;
item->setSizeHint(QSize(this->width(), 10));
item->setData(status.message(), StatusWidgetDelegate::MessageRole);

model()->insertRow(row,item);
}


void List::resizeEvent(QResizeEvent *e)
{
for( int i = 0; i < model()->rowCount(); i++)
{
model()->item(i)->setSizeHint(QSize(this->width(),10));
}
}

QStyledItemDelegate


StatusWidgetDelegate::StatusWidgetDelegate(QObject *parent) :
QStyledItemDelegate(parent), m_currentItemHeight(0)
{
}

QSize StatusWidgetDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QString text = index.data(MessageRole).toString();
QRectF r = option.rect;
QFontMetricsF fm(QApplication::font());
m_currentItemHeight = fm.boundingRect(r, Qt::AlignJustify | Qt::AlignVCenter | Qt::TextWordWrap, text).height();

QSize size = QStyledItemDelegate::sizeHint(option, index);
size.setHeight(m_currentItemHeight);
size.setWidth(size.width() - 10);

return size;
}

void StatusWidgetDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QString text = index.data(MessageRole).toString();
QRectF r = option.rect;
painter->save();
painter->setPen(Qt::NoPen);
painter->setBrush(QColor(220,220,250));
painter->drawRect(r);
painter->restore();
painter->drawText(r, Qt::AlignJustify | Qt::AlignVCenter | Qt::TextWordWrap, text);
}

Thanks for looking...

Added after 47 minutes:

The other thing is that a QListView scroll bar does not react on new delegates. Moving Bottom Window up to resize a height of the entire mainWindow does not show a QListView scroll bar. so long list items is behind and not visible.

Something is wrong here.

Lykurg
28th December 2011, 17:42
pff! That was an old wiki article I wrote without ever polish it...

If I understand you right, you just want a list with different row heights to fit the content. It is as simple as this

#include <QtGui>


class Delegate : public QItemDelegate
{
public:
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const {
return option.fontMetrics.boundingRect(option.rect, Qt::TextWordWrap, index.data().toString()).size();
}
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const {
if (option.state & QStyle::State_Selected) {
painter->fillRect(option.rect, option.palette.highlight());
painter->setPen(option.palette.highlightedText().color());
} else {
painter->setPen(option.palette.text().color());
}
painter->drawText(option.rect, Qt::TextWordWrap, index.data().toString());
}
};

int main(int argC, char **argV)
{
QApplication myApp(argC, argV);
QStringListModel m;
m.setStringList(QStringList()
<< "test"
<< "long test long test long test long test"
<< "even longer test even longer test even longer test even longer test even "
"longer test even longer test even longer test even longer test even longer "
"test even longer test even longer test even longer test even longer test "
"even longer test");

Delegate d;
QListView v;
v.setItemDelegate(&d);
v.setModel(&m);
v.show();

return myApp.exec();
}


Best