原生 QStyledItemDelegate.draw() 在使用 QStandardItemModel 渲染 QListView 时如何工作?

问题描述 投票:0回答:0

问题来自于做选择窗口时的一个简单需求:

image of ui

你们可以看到它是一个

QListView
显示文件列表,然后选择用户需要的文件,确认并关闭。

原生

QListView
只显示一行数据,在
Qt.DisplayRole
中。我需要添加第二行文本,显示文件大小、修改时间、目录等内容

所以在询问ChatGPT和搜索之后,我知道我需要将自己的数据存储在

Qt.UserRole
中应用自定义
QStyledItemDelegate
QListView
,重写它的
paint()
方法。

Native

paint()
很好地处理复选框和装饰图标。我只需要在渲染
Qt.DisplayRole
时添加第二行。然后我发现
paint()
渲染项目作为一个整体,我必须从零开始写一切。

我只能从这里找到C++ src:

/*!
    Renders the delegate using the given \a painter and style \a option for
    the item specified by \a index.

    This function paints the item using the view's QStyle.

    When reimplementing paint in a subclass. Use the initStyleOption()
    to set up the \a option in the same way as the
    QStyledItemDelegate.

    Whenever possible, use the \a option while painting.
    Especially its \l{QStyleOption::}{rect} variable to decide
    where to draw and its \l{QStyleOption::}{state} to determine
    if it is enabled or selected.

    After painting, you should ensure that the painter is returned to
    the state it was supplied in when this function was called.
    For example, it may be useful to call QPainter::save() before
    painting and QPainter::restore() afterwards.

    \sa QItemDelegate::paint(), QStyle::drawControl(), QStyle::CE_ItemViewItem
*/
void QStyledItemDelegate::paint(QPainter *painter,
        const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    Q_ASSERT(index.isValid());

    QStyleOptionViewItem opt = option;
    initStyleOption(&opt, index);

    const QWidget *widget = QStyledItemDelegatePrivate::widget(option);
    QStyle *style = widget ? widget->style() : QApplication::style();
    style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, widget);
}

来自PySide6文档

如果代理不支持你需要的数据类型的绘制或者你想自定义项目的绘制,你需要子类化 QStyledItemDelegate ,并重新实现 paint() 和可能的 sizeHint() 。 paint() 函数为每个项目单独调用,并使用 sizeHint() ,您可以为每个项目指定提示。

重新实现 paint() 时,通常会处理想要绘制的数据类型,并将超类实现用于其他类型。

复选框指示器的绘制由当前样式执行。该样式还指定了为不同数据角色绘制数据的大小和边界矩形。项目本身的边界矩形也是由样式计算的。因此,当绘制已经支持的数据类型时,最好询问这些边界矩形的样式。 QStyle 类描述对此进行了更详细的描述。

如果您希望更改任何由样式计算的边界矩形或复选框指示器的绘制,您可以子类化 QStyle 。但是请注意,重新实现 sizeHint() 也会影响项目的大小。

作为 QT 的新手,我无法处理这么多的 StateFlags 和主题样式,尝试编写一个没有任何 Hover / Selected / OutOfFocus 样式更改的“死” ui.

我终于用愚蠢但有效的方式实现了我的需求:

  1. '\n'
    后添加一个
    Qt.DisplayRole
    为一个项目,
  2. 对列表项使用原生对齐方式 (
    AlignVCenter | AlignLeft
    ),
  3. 打电话
    super().paint(painter, option, index)

然后 Qt 将以 2 倍行高呈现

DisplayRole
,但第 2 行为空。

  1. 使用
    painter.drawText()
    option.font
    option.fontMetrics
    、从
    option.rect
  2. 计算的QRect绘制额外的文本

image of code

我也按照本指南成功绘制了复选框,用python重写了cpp代码逻辑。结果点了之后没有反应。它的状态总是“未检查”。


我的问题是,如何尽可能“本地”实现我的需求?


类似的做法:

How to paint() with QStyledItemDelegate

python pyside pyside6 qlistview qstyleditemdelegate
© www.soinside.com 2019 - 2024. All rights reserved.