He estado luchando con esto por algunas veces, y parece que no puedo encontrar la manera correcta de hacerlo.¿Cuál es la mejor manera de mostrar un icono animado en un QTableView?
Lo que me gustaría es la posibilidad de utilizar un ícono animado como decoración para algunos de mis artículos (generalmente para mostrar que se está procesando algo para este artículo en particular). Tengo un modelo de tabla personalizado, que se muestra en un QTableView
.
Mi primera idea fue crear un delegado personalizado que se ocuparía de mostrar la animación. Cuando haya aprobado QMovie
para la función de decoración, el delegado se conectará al QMovie
para actualizar la pantalla cada vez que haya un nuevo fotograma disponible (consulte el código a continuación). Sin embargo, el pintor no parece seguir siendo válido después de la llamada al método paint
del delegado (me aparece un error al llamar al método save
del pintor, probablemente porque el puntero ya no apunta a la memoria válida).
Otra solución sería emitir la señal dataChanged
del artículo cada vez que hay un nuevo fotograma disponible, pero 1) que provocaría muchos gastos generales innecesarios, ya que los datos no se modifican realmente; 2) no parece realmente limpio manejar la película en el nivel del modelo: debe ser la responsabilidad del nivel de visualización (QTableView
o el delegado) manejar la visualización de nuevos marcos.
¿Alguien conoce una forma limpia (y preferiblemente eficiente) de mostrar la animación en las vistas Qt?
Para los 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 * >();
}
he encontrado algo bastante similar en [ 'QxtItemDelegate'] (http://www.koders.com/cpp/fid5911A4434425C7038B6C507A5BF978C82A6294FD.aspx), una extensión a' QtItemDelegate' que permiten dibujar las barras de progreso (entre otras cosas) Para hacerlo, este delegado utiliza un enfoque bastante similar al propuesto en mi pregunta, pero almacena vistas e índices en lugar de pintores; en cada tiempo de espera de un temporizador, el delegado actualiza todas las vistas, preferiblemente solo los elementos que necesitan actualización. –