c++ - 如何为 QListView 中列表项的边框设置动画?

标签 c++ qt qt5 qlistview qstyleditemdelegate

我正在使用带有从 QStyledItemDelegate 扩展的自定义委托(delegate)的 QListView。我重新实现了绘制方法来自定义绘制列表中的每个项目。在绘制方法中,我在 ListView 中的选定项目周围绘制边框。

我希望能够在选择项目时为项目边框设置动画。例如,如果预期项目边框为 5 像素,我希望在选择该项目时使其在 0 像素到 5 像素之间“动画化”。

我最初的想法是连接一个计时器,每 50 毫秒触发一次,并在每次计时器触发时让委托(delegate)进行绘制,直到绘制完整个边框宽度。但是,委托(delegate)重新实现的绘制方法是常量,因此我无法在每次调用绘制方法期间保存或更新边框宽度成员变量。

实现这一目标的最佳方法是什么?

最佳答案

一个可能的解决方案是创建一个管理项目边框大小的角色,并使用QVariantAnimation更新它:

#include <QApplication>
#include <QListView>
#include <QPainter>
#include <QStandardItemModel>
#include <QStyledItemDelegate>
#include <QVariantAnimation>

int BorderSizeRole = Qt::UserRole+1;

class AnimationDelegate: public QStyledItemDelegate{
public:
    using QStyledItemDelegate::QStyledItemDelegate;
    void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const{
        QStyledItemDelegate::paint(painter, option, index);

        bool ok;
        int borderSize = index.data(BorderSizeRole).toInt(&ok);
        if(borderSize >0 && ok){
            painter->save();
            QPen pen(QBrush(Qt::red), borderSize);
            painter->setPen(pen);
            painter->drawRect(option.rect);
            painter->restore();
        }
    }
};

class CustomAnimation: public QVariantAnimation{
    QPersistentModelIndex m_index;
    QAbstractItemModel *m_model;
public:
    CustomAnimation(QAbstractItemModel *m_model, QPersistentModelIndex index, QObject *parent=nullptr)
        : QVariantAnimation(parent),
          m_index(index),
          m_model(m_model)
    {
        setStartValue(0);
        setEndValue(5);
        setDuration(50*5);
        connect(this, &CustomAnimation::valueChanged, this, &CustomAnimation::on_valueChanged);
        // delete animation
        start(QAbstractAnimation::DeleteWhenStopped);
    }
private:
    Q_SLOT void on_valueChanged(const QVariant & value){
        if(m_model)
            m_model->setData(m_index, value, BorderSizeRole);
        else
            stop();
    }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QListView view;
    view.setItemDelegate(new AnimationDelegate(&view));
    QStandardItemModel model;
    for(int i=0; i<10; i++){
        QStandardItem *item = new QStandardItem(QString("item %1").arg(i));
        item->setData(-1, BorderSizeRole);
        model.appendRow(item);
    }
    view.setModel(&model);

    QObject::connect(view.selectionModel(), &QItemSelectionModel::selectionChanged,
                     [&model](const QItemSelection &selected, const QItemSelection & deselected){
        for(const QModelIndex & index: selected.indexes()){
            new CustomAnimation(&model, QPersistentModelIndex(index));
        }
        // remove border
        for(const QModelIndex & index: deselected.indexes()){
            model.setData(index, -1, BorderSizeRole);
        }
    });

    view.show();    
    return a.exec();
}

关于c++ - 如何为 QListView 中列表项的边框设置动画?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50240983/

相关文章:

c++ - 如何 stub /模拟 Qt 类?

c++ - 使 DEV++ 与 Turbo C++ 的代码/ header 兼容

c++ - 检查 QFont 是 Serif 还是 Sans-Serif

qt - QTableView 列的相对大小提示

c++ - 交叉编译 Qt 5

c++ - 从 C++ 中的 QML-矩形请求键盘焦点

c++ - 如何在 Qt 中分层独立的小部件?

c++ - 为什么通过引用传递变量比全局定义变量慢?

css - 使用 "Less"或类似的东西生成 Qt 样式表

c++ - 使用 Visual Studio 构建 QT