c++ - 在 QTableView 中显示动画图标的最佳方式是什么?

标签 c++ qt qtableview qabstracttablemodel

我已经为此苦苦挣扎了一段时间,但我似乎找不到正确的方法来做到这一点。

我想要的是能够使用动画图标作为我的某些项目的装饰(通常是为了表明正在对该特定项目进行某些处理)。我有一个自定义表格模型,我将其显示在 QTableView 中。

我的第一个想法是创建一个自定义委托(delegate)来负责显示动画。当为装饰角色传递 QMovie 时,委托(delegate)将连接到 QMovie 以便在每次有新帧可用时更新显示(请参见下面的代码)。然而,在调用委托(delegate)的paint方法后,painter似乎并没有保持有效(我在调用painter的save方法时出错,可能是因为指针不再指向有效内存)。

另一种解决方案是在每次有新帧可用时发出项目的 dataChanged 信号,但是 1) 这会导致许多不必要的开销,因为数据并没有真正改变; 2) 在模型级别处理电影似乎并不干净:处理新帧的显示应该是显示层(QTableView 或委托(delegate))的责任。

有谁知道在 Qt View 中显示动画的简洁(最好是高效)方式?


有兴趣的可以看看我自己开发的delegate的代码(暂时不能用)

// Class that paints movie frames every time they change, using the painter
// and style options provided
class MoviePainter : public QObject
{
    Q_OBJECT

  public: // member functions
    MoviePainter( QMovie * movie, 
                  QPainter * painter, 
                  const QStyleOptionViewItem & option );

  public slots:
    void paint( ) const;

  private: // member variables
    QMovie               * movie_;
    QPainter             * painter_;
    QStyleOptionViewItem   option_;
};


MoviePainter::MoviePainter( QMovie * movie,
                            QPainter * painter,
                            const QStyleOptionViewItem & option )
  : movie_( movie ), painter_( painter ), option_( option )
{
    connect( movie, SIGNAL( frameChanged( int ) ),
             this,  SLOT( paint( ) ) );
}

void MoviePainter::paint( ) const
{
    const QPixmap & pixmap = movie_->currentPixmap();

    painter_->save();
    painter_->drawPixmap( option_.rect, pixmap );
    painter_->restore();
}

//-------------------------------------------------

//Custom delegate for handling animated decorations.
class MovieDelegate : public QStyledItemDelegate
{
    Q_OBJECT

  public: // member functions
    MovieDelegate( QObject * parent = 0 );
    ~MovieDelegate( );

    void paint( QPainter * painter, 
                const QStyleOptionViewItem & option, 
                const QModelIndex & index ) const;

  private: // member functions
    QMovie * qVariantToPointerToQMovie( const QVariant & variant ) const;

  private: // member variables
    mutable std::map< QModelIndex, detail::MoviePainter * > map_;
};

MovieDelegate::MovieDelegate( QObject * parent )
  : QStyledItemDelegate( parent )
{
}

MovieDelegate::~MovieDelegate( )
{
    typedef  std::map< QModelIndex, detail::MoviePainter * > mapType;

          mapType::iterator it = map_.begin();
    const mapType::iterator end = map_.end();

    for ( ; it != end ; ++it )
    {
        delete it->second;
    }
}

void MovieDelegate::paint( QPainter * painter, 
                           const QStyleOptionViewItem & option, 
                           const QModelIndex & index ) const
{
    QStyledItemDelegate::paint( painter, option, index );

    const QVariant & data = index.data( Qt::DecorationRole );

    QMovie * movie = qVariantToPointerToQMovie( data );

    // Search index in map
    typedef std::map< QModelIndex, detail::MoviePainter * > mapType;

    mapType::iterator it = map_.find( index );

    // if the variant is not a movie
    if ( ! movie )
    {
        // remove index from the map (if needed)
        if ( it != map_.end() )
        {
            delete it->second;
            map_.erase( it );
        }

        return;
    }

    // create new painter for the given index (if needed)
    if ( it == map_.end() )
    {
        map_.insert( mapType::value_type( 
                index, new detail::MoviePainter( movie, painter, option ) ) );
    }
}

QMovie * MovieDelegate::qVariantToPointerToQMovie( const QVariant & variant ) const
{
    if ( ! variant.canConvert< QMovie * >() ) return NULL;

    return variant.value< QMovie * >();
}

最佳答案

最好的解决方案是使用 QSvgRenderer在委托(delegate)中。

enter image description here

它很容易实现,与 gif 不同,SVG 是轻量级的并且支持透明。

    TableViewDelegate::TableViewDelegate(TableView* view, QObject* parent)
    : QStyledItemDelegate(parent), m_view(view)
{
    svg_renderer = new QSvgRenderer(QString{ ":/res/img/spinning_icon.svg" }, m_view);

    connect(svg_renderer, &QSvgRenderer::repaintNeeded,
        [this] {
        m_view->viewport()->update();
    });
}


void TableViewDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option,
    const QModelIndex& index) const
{
    QStyleOptionViewItem opt{ option };
    initStyleOption(&opt, index);

    if (index.column() == 0) {
        if (condition)
        {
            // transform bounds, otherwise fills the whole cell
            auto bounds = opt.rect;
            bounds.setWidth(28);
            bounds.moveTo(opt.rect.center().x() - bounds.width() / 2,
                opt.rect.center().y() - bounds.height() / 2);

            svg_renderer->render(painter, bounds);
        }
    }

    QStyledItemDelegate::paint(painter, opt, index);
}

Here's一个不错的网站,您可以在其中生成自己的旋转图标并以 SVG 格式导出。

关于c++ - 在 QTableView 中显示动画图标的最佳方式是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4361366/

相关文章:

c++ - 从函数双端队列上的迭代器获取函数指针

qt - 在图形 View 中显示图 block map 和其他对象的最佳方式是什么?

qt - qml中如何断开一个信号的方法?

qt - 使用 CLion 编辑 ui 文件

qt - 如何仅使用 CSS 在 Qt 中的 QTableView 的标题中对齐文本?

python - 如何改变QTableView图像大小

c++ - 在 vector 上调用 push_back 时出现段错误

C++ - 结合 typedef 和 typename 的语句的含义

c++ - 对包含索引小部件的 QTableView 列进行排序

c++ - 在 Go (golang) 和 C++ 之间交换数据结构(数组)