Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to add a custom widget into a QListView?

Tags:

c++

qt

qlistview

I have a large log data (100, 1000, 100000, ... records) and I want to visualize it in the following manner:

enter image description here enter image description here enter image description here

Which widget (e.g. QListView, QListWidget) should I use and how, in order to stay away from performance and memory problems?

like image 387
Bahramdun Adil Avatar asked Nov 01 '18 16:11

Bahramdun Adil


1 Answers

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

Solution

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:

  1. Create a subclass of QStyledItemDelegate, say Delegate

  2. Reimplement the QStyledItemDelegate::paint method to do the custom drawing

  3. Reimplement the QStyledItemDelegate::sizeHint to report the correct size of the items in the list

  4. Use the custom delegate in the view by calling QAbstractItemView::setItemDelegate

Example

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.

Result

As written, the given example produces the following result:

Window with a message logger

like image 89
scopchanov Avatar answered Nov 15 '22 05:11

scopchanov