是否可以将自定义小部件添加到 QListView 中?

Bah*_*dil 5 c++ qt qlistview

我有一个很大的日志数据(100、1000、100000、...记录),我想以下列方式将其可视化:

在此处输入图片说明 在此处输入图片说明 在此处输入图片说明

为了避免性能和内存问题,我应该使用哪个小部件(例如QListView, QListWidget)以及如何使用?

sco*_*nov 12

是否可以将自定义小部件添加到 QListView 中?

请阅读:

如何在 Qt C++ 应用程序中显示带有大量小部件的可滚动列表作为项目?


我想以上述格式显示每条日志消息

解决方案

为了达到预期的结果并远离性能问题,即使数据日志很长,也可以使用QListView自定义委托:

  1. 创建一个子类QStyledItemDelegate,比如说Delegate

  2. 重新实现QStyledItemDelegate::paint自定义绘图的方法

  3. 重新实现QStyledItemDelegate::sizeHint以报告列表中项目的正确大小

  4. 通过调用在视图中使用自定义委托 QAbstractItemView::setItemDelegate

例子

我为您准备了一个工作示例,以演示如何在应用程序中实施和使用建议的解决方案。

该示例的基本部分是委托在列表视图中绘制项目的方式:

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();
}
Run Code Online (Sandbox Code Playgroud)

该示例的完整代码可在GitHub找到

结果

如所写,给定的示例产生以下结果:

带有消息记录器的窗口

  • 谢谢回复!但是我觉得Qt让这个功能的实现变得非常复杂,并不是一个很好的Model和View的概念,所有的事情都需要大量的代码来完成,所有的绘制都是手动完成的。对于一个简单的列表,你需要编写大量的代码和文件。我觉得应该和Android ListView一样,只需要一个Model列表和items视图,所有的事情都在ListView引擎内部完成。这在很大程度上降低了代码的复杂性,减少了 BUG 的机会。 (2认同)
  • @BahramdunAdil,Qt 小部件可以轻松创建本机外观的 GUI。当您想要自定义外观时,您可以使用项目视图的自定义委托(如我的答案中所示),或者创建自定义样式,或者使用 QML。在 SO 上有很多关于每种方法的信息。然而,在一个主题中讨论所有这些超出了该网站的范围。首先,你的问题太宽泛了,将其缩小到可回答的范围是一个挑战,我做到了,并且提供了一个如何实现你想要的目标的工作示例。请不要让问题变得更广泛。 (2认同)