【发布时间】:2011-05-20 16:02:54
【问题描述】:
我已经为此苦苦挣扎了一段时间,但似乎找不到正确的方法。
我想要的是能够使用动画图标作为我的一些项目的装饰(通常表明正在对这个特定项目进行一些处理)。我有一个自定义表格模型,我在 QTableView 中显示。
我的第一个想法是创建一个负责显示动画的自定义委托。当为装饰角色传递QMovie 时,委托将连接到QMovie,以便在每次有新框架可用时更新显示(参见下面的代码)。但是,在调用委托的paint 方法后,painter 似乎不再有效(调用painter 的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 * >();
}
【问题讨论】:
-
我在
QxtItemDelegate中发现了一些非常相似的东西,它是QtItemDelegate的扩展,它可以绘制进度条(除其他外)。为此,该委托使用的方法与我在问题中提出的方法非常相似,但它存储视图和索引而不是画家;在计时器每次超时时,委托更新所有视图,最好只更新需要更新的项目。
标签: c++ qt qtableview qabstracttablemodel