私はこれにしばらく苦労してきましたが、これを行う正しい方法を見つけることができないようです。
私が望むのは、いくつかのアイテムの装飾としてアニメーション化されたアイコンを使用する機能です (通常、この特定のアイテムに対して何らかの処理が行われていることを示すため)。に表示するカスタム テーブル モデルがあり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 * >();
}