Я боролся с этим уже несколько раз, и я не могу найти правильный способ сделать это.
Что мне хотелось бы, так это возможность использовать анимированный значок в качествеукрашение для некоторых из моих предметов (как правило, чтобы показать, что для этого конкретного предмета происходит некоторая обработка).У меня есть пользовательская модель таблицы, которую я отображаю в QTableView
.
Моя первая идея состояла в том, чтобы создать пользовательский делегат, который позаботится об отображении анимации.Когда передается QMovie
для роли оформления, делегат подключается к QMovie
, чтобы обновлять отображение каждый раз, когда доступен новый кадр (см. Код ниже).Однако кажется, что художник не остается действительным после вызова метода делегата paint
(я получаю ошибку при вызове метода save
художника, возможно, потому, что указатель больше не указывает на действительную память).
Другое решение состояло бы в том, чтобы испускать сигнал dataChanged
элемента каждый раз, когда доступен новый кадр, но 1) это вызвало бы много ненужных служебных данных, поскольку данные на самом деле не изменились;2) кажется, что обработка фильма на уровне модели не совсем чистая: ответственность за отображение новых кадров должна лежать на уровне отображения (QTableView
или делегат).
Кто-нибудьзнаете чистый (и желательно эффективный) способ отображения анимации в представлениях Qt?
Для тех, кто интересуется, вот код делегата, которого я разработал (который не работает в данный момент).
// 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 * >();
}