¿Cuál es la mejor manera de mostrar un icono animado en un QTableView?

He estado luchando con esto por algunas veces, y parece que no puedo encontrar la manera correcta de hacerlo.

Lo que me gustaría es la capacidad de usar un ícono animado como decoración para algunos de mis artículos (generalmente para mostrar que se está produciendo algún procesamiento para este artículo en particular). Tengo un modelo de tabla personalizado, que muestro en unQTableView.

Mi primera idea fue crear un delegado personalizado que se encargaría de mostrar la animación. Cuando pasó unQMovie para el rol de decoración, el delegado se conectaría alQMovie para actualizar la pantalla cada vez que hay un nuevo marco disponible (vea el código a continuación). Sin embargo, el pintor no parece seguir siendo válido después de la llamada al delegado.paint método (obtengo un error al llamar al pintorsave método, probablemente porque el puntero ya no apunta a memoria válida).

Otra solución sería emitir eldataChanged señal del elemento cada vez que hay un nuevo marco disponible, pero 1) eso induciría una sobrecarga innecesaria, ya que los datos no cambian realmente; 2) no parece realmente limpio manejar la película a nivel de modelo: debería ser responsabilidad del nivel de visualización (QTableView o el delegado) para manejar la visualización de nuevos marcos.

¿Alguien sabe una forma limpia (y preferiblemente eficiente) de mostrar animación en vistas Qt?

Para aquellos interesados, aquí está el código del delegado que desarrollé (que no funciona en este momento).

// 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 * >();
}

Respuestas a la pregunta(1)

Su respuesta a la pregunta