How to create QListView item with different heights
-
I am trying to create a ListView which the item does not have a specific height, 64~n, so when adding a new Item to the list also needs to give the height also, but I don't know the exact height of the text which is going be shown in the list.
Here is when add new Item to the list:
void LogListView::addMessage(const QJsonObject &msg, const bool append) { static int id = 1; // unique id for log items auto *item = new QStandardItem(); item->setEditable(false); item->setData(QString("%1").arg(id++, 5, 10, QChar('0')), LogListItemDelegate::DT_Id); item->setData(msg["icon"], LogListItemDelegate::DT_ICON); item->setData(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss"), LogListItemDelegate::DT_Timestamp); item->setData(msg["title"], LogListItemDelegate::DT_Title); item->setData(msg["subtitle"], LogListItemDelegate::DT_Subtitle); item->setData(msg["details"], LogListItemDelegate::DT_Details); item->setData(false, LogListItemDelegate::DT_Expanded); //item->setSizeHint(QSize(0, 64)); // here is the exact height cannot be calculated static_cast<QStandardItemModel *>(model())->appendRow(item); scrollToBottom(); }
And here is when drawing the data on List Item:
void LogListItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QStyleOptionViewItem opt = option; QString icon = index.data(DT_ICON).toString(); if(icon == "1") { // normal icon = ":/icons/status-ok.png"; } else if(icon == "2") { // warning icon = ":/icons/status-warn.png"; } else { // error icon = ":/icons/status-error.png"; } QString id = index.data(DT_Id).toString(); QString timestamp = index.data(DT_Timestamp).toString(); QString title = index.data(DT_Title).toString(); QString subtitle = index.data(DT_Subtitle).toString(); bool hovered = opt.state & QStyle::State_MouseOver; QFont f(opt.font); f.setPointSize(10); painter->save(); // draw hover if(hovered) { painter->fillRect(opt.rect.adjusted(0, 0, 0, 0), "#E6E6E6"); } // Draw message icon painter->drawPixmap(8, opt.rect.y() + 8, QIcon(icon).pixmap(32, 32)); // Draw id painter->setFont(f); painter->setPen(opt.palette.text().color()); painter->drawText(opt.rect.adjusted(48, 8, 0, 0), Qt::TextSingleLine, id); // Draw timestamp painter->setFont(f); int wTimestamp = painter->fontMetrics().boundingRect(timestamp).width(); painter->setPen(opt.palette.text().color()); painter->drawText(opt.rect.adjusted((opt.rect.width()/2)-(wTimestamp/2), 8, 0, 0), Qt::TextSingleLine, timestamp); // Draw title QFont fntTitle(opt.font); fntTitle.setBold(true); fntTitle.setPointSize(12); painter->setFont(fntTitle); painter->setPen(opt.palette.windowText().color()); painter->drawText(opt.rect.adjusted(48, 32, 0, 0), Qt::TextSingleLine, title); // Draw subtile int wTitle = painter->fontMetrics().boundingRect(title).width(); QFont fntSubTitle(opt.font); fntTitle.setPointSize(10); painter->setFont(fntSubTitle); painter->setPen(opt.palette.windowText().color()); painter->drawText(opt.rect.adjusted(48+wTitle+12, 32, 0, 0), Qt::TextSingleLine, subtitle); //expand icon QString details = index.data(DT_Details).toString(); QFont fntDetials(opt.font); painter->setFont(fntDetials); fntDetials.setPointSize(12); painter->setPen(opt.palette.windowText().color()); painter->drawText(opt.rect.adjusted(48, 32+32, 0, 0), Qt::TextWordWrap, details); painter->restore(); }
And here is when returning the sizeHint():
QSize LogListItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { // bool expanded = index.data(DT_Expanded).toBool(); // QFont fntDetials = option.font; // fntDetials.setPointSize(12); // QRect r = option.rect; // QFontMetrics fm(fntDetials); // QString details = index.data(DT_Details).toString(); // QRect br = fm.boundingRect(r, Qt::TextWordWrap, details); // return QSize(option.rect.width(), br.height()+64); QSize result = QStyledItemDelegate::sizeHint(option, index); result.setHeight(result.height()*2); return result; //QSize s = QStyledItemDelegate::sizeHint(option, index); // QFont fntDetials = option.font; // fntDetials.setPointSize(12); // QRect r = option.rect; // QFontMetrics fm(fntDetials); // QString details = index.data(DT_Details).toString(); // QRect br = fm.boundingRect(r, Qt::TextWordWrap, details); // s.setHeight(br.height()); //return s; }
But the result always not correct, sometimes it is very small to fit the content and sometimes is very large for a small content, and so on...
And also when resizing the window, also will cause content to not fit the height.I really want to ask: Why Qt decided to create such kind of ListView which is really very hard to use when there is a very complex data to show, all things need to draw by myself, calculate a lot of x,y positions, padding, .... etc.
Why there is not something like Android ListView, which only needs to set the Item layout and give the data to populate on. And the ListView itself will take care of everything inside the item, and also by using the view holder recycle the items view, which solves the memory waste problem. BUT Qt makes it very hard to use, everything must be done by myself, the ListView does nothing.? And also there is no any good tutorial to show how to use for different cases such as specific, non-specific height and width, resizing and so on...Thanks!
Note: this problem wastes me a lot of time, till now I am not able to solve.