I have a large log data (100, 1000, 100000, ... records) and I want to visualize it in the following manner:
Which widget (e.g. QListView
, QListWidget
) should I use and how, in order to stay away from performance and memory problems?
I have a large log data (100, 1000, 100000, ... records) and I want to visualize it in the following manner:
Which widget (e.g. QListView
, QListWidget
) should I use and how, in order to stay away from performance and memory problems?
Is it possible to add a custom widget into a QListView?
Please, read about:
How to display a scrollable list with a substantial amount of widgets as items in a Qt C++ app?
I want to show every log message in the above format
To achieve the desired result and stay away from performance issues, even with a very long data log, use a QListView
with a custom delegate:
Create a subclass of QStyledItemDelegate
, say Delegate
Reimplement the QStyledItemDelegate::paint
method to do the custom drawing
Reimplement the QStyledItemDelegate::sizeHint
to report the correct size of the items in the list
Use the custom delegate in the view by calling QAbstractItemView::setItemDelegate
I have prepared a working example for you in order to demonstrate how the proposed solution could be implemented and used in an application.
The essential part of the example is the way the delegate paints the items in the list view:
void Delegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
QStyleOptionViewItem opt(option);
initStyleOption(&opt, index);
const QPalette &palette(opt.palette);
const QRect &rect(opt.rect);
const QRect &contentRect(rect.adjusted(m_ptr->margins.left(),
m_ptr->margins.top(),
-m_ptr->margins.right(),
-m_ptr->margins.bottom()));
const bool lastIndex = (index.model()->rowCount() - 1) == index.row();
const bool hasIcon = !opt.icon.isNull();
const int bottomEdge = rect.bottom();
QFont f(opt.font);
f.setPointSize(m_ptr->timestampFontPointSize(opt.font));
painter->save();
painter->setClipping(true);
painter->setClipRect(rect);
painter->setFont(opt.font);
// Draw background
painter->fillRect(rect, opt.state & QStyle::State_Selected ?
palette.highlight().color() :
palette.light().color());
// Draw bottom line
painter->setPen(lastIndex ? palette.dark().color()
: palette.mid().color());
painter->drawLine(lastIndex ? rect.left() : m_ptr->margins.left(),
bottomEdge, rect.right(), bottomEdge);
// Draw message icon
if (hasIcon)
painter->drawPixmap(contentRect.left(), contentRect.top(),
opt.icon.pixmap(m_ptr->iconSize));
// Draw timestamp
QRect timeStampRect(m_ptr->timestampBox(opt, index));
timeStampRect.moveTo(m_ptr->margins.left() + m_ptr->iconSize.width()
+ m_ptr->spacingHorizontal, contentRect.top());
painter->setFont(f);
painter->setPen(palette.text().color());
painter->drawText(timeStampRect, Qt::TextSingleLine,
index.data(Qt::UserRole).toString());
// Draw message text
QRect messageRect(m_ptr->messageBox(opt));
messageRect.moveTo(timeStampRect.left(), timeStampRect.bottom()
+ m_ptr->spacingVertical);
painter->setFont(opt.font);
painter->setPen(palette.windowText().color());
painter->drawText(messageRect, Qt::TextSingleLine, opt.text);
painter->restore();
}
The complete code of the example is available on GitHub.
As written, the given example produces the following result:
QSize(index.data(Qt::SizeHintRole).toSize().width(), 64);
Here you hardcoded 64, but it is not something I want, because log message can be very long or very short depends on system what log it sends. –
Yvette © 2022 - 2025 — McMap. All rights reserved.
QTextEdit
withreadOnly(true)
. As it supports rich-texts, I can start the log output lines with the appropriate icons. If the log becomes very long, then it could be an option to make a bit more effort and cache only part of the data while loading more when near top/bottom. However, this can cause some fiddling to adjust scrollbars properly. – GapinQListWiget
vs.QListView
: The former is derived from the latter. WhileQListWidget
might be more convenient to use, it might cause a certain overhead. – Gapin