Мой ответ для людей, которые, как я некоторое время назад, реализуют логику режима рендеринга в их методе GraphicsItem::paint()
.
Например:
GraphicsItem::paint(QPainter * painter, const QStyleOptionGraphicsItem*, QWidget*)
{
QPen _pen ;
const qreal normalPenWidthF = 1.5 ;
if(isSelected()) {
_pen.setColor(Settings::s_selectionColor) ;
_pen.setWidthF(Settings::s_selectionWidth) ;
}
else
if(isHovered()) {
_pen.setColor(Settings::s_hoveredColor) ;
_pen.setWidthF(Settings::s_selectionWidth) ;
}
else
if(someOtherLogic()) {
_pen.setColor(Settings::s_otherColor) ;
_pen.setWidthF(normalPenWidthF) ;
}
else {
_pen.setColor(TSPSettings::s_defaultColor) ;
_pen.setWidthF(normalPenWidthF) ;
}
//
painter->setPen(_pen) ;
painter->setBrush(Qt::NoBrush) ;
painter->drawEllipse(m_rect) ;
}
Вот как я добился хорошей производительности QGraphicsView, даже с большими сценами, включающими несколько слоев. Он может даже поддерживать динамическое усечение фигур между слоями.
- Пользовательские графические элементы должны наследовать QAbstractGraphicsShapeItem,
поэтому у вас есть поддержка setPen () и setBrush ().
- Предоставьте интерфейс для обновления пера и кисти и используйте некоторую логику для
запускать обновление только при необходимости.
.h
class AbstractGraphicsItem : public QAbstractGraphicsShapeItem
{
private :
bool m_hovered ;
public :
AbstractGraphicsItem() ;
virtual ~AbstractGraphicsItem() ;
bool isHovered() const { return m_hovered ; }
void setIsHovered(bool state) ;
// control render mode update
virtual void updatePenAndBrush()=0 ;
protected :
virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value) ;
virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *e);
virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *e);
};
.cpp
AbstractGraphicsItem::AbstractGraphicsItem()
: QAbstractGraphicsShapeItem()
, m_hovered(false)
{
}
AbstractGraphicsItem::~AbstractGraphicsItem()
{
}
void AbstractGraphicsItem::setHovered(bool state)
{
if (h!=isHovered()) {
m_hovered = h ;
updatePenAndBrush() ;
update() ;
}
}
void AbstractGraphicsItem::hoverEnterEvent(QGraphicsSceneHoverEvent*)
{
setHovered(true) ;
}
void AbstractGraphicsItem::hoverLeaveEvent(QGraphicsSceneHoverEvent*)
{
setHovered(false) ;
}
QVariant AbstractGraphicsItem::itemChange(GraphicsItemChange change, const QVariant &value)
{
switch(change) {
case ItemSelectedHasChanged :
updatePenAndBrush() ;
break ;
}
return QAbstractGraphicsShapeItem::itemChange(change, value);
}
И тогда ваш GraphicsItem
(который наследует AbstractGraphicsItem
) становится:
void GraphicsItem::updatePenAndBrush()
{
QPen _pen ;
if(isSelected()) {
_pen.setColor(Settings::s_selectionColor) ;
_pen.setWidthF(Settings::s_selectionWidth) ;
} else
if(isHovered()) {
_pen.setColor(Settings::s_hoveredColor) ;
_pen.setWidthF(Settings::s_selectionWidth) ;
} else
if(someOtherLogic()) {
_pen.setColor(Settings::s_otherColor) ;
_pen.setWidthF(normalPenWidthF) ;
} else {
_pen.setColor(Settings::s_defaultColor) ;
_pen.setWidthF(normalPenWidthF) ;
}
_pen.setCosmetic(true) ;
setPen(_pen) ;
}
void GraphicsItem::paint(QPainter *painter, const QStyleOptionGraphicsItem*, QWidget *)
{
painter->setPen(pen()) ;
painter->setBrush(brush()) ;
painter->drawEllipse(s_rect) ;
}
Содержимое старого метода GraphicsItem::paint()
теперь находится в GraphicsItem::updatePenAndBrush()
и вызывается время от времени, но не при каждом вызове рисования. С другой стороны, метод рисования доходит до основ.
Очевидно, вам придется позвонить updatePenAndBrush()
самостоятельно, но в моем случае это было несложно.
Это не единственное, что я сделал, чтобы улучшить производительность. Я много искал, и есть много возможностей для настройки системы Graphics View, но с этим мое приложение перешло от едва пригодного к использованию в реальном времени (наконец-то!)