QGraphicsItem::ItemIgnoresTransformations issue



  • I am trying to create an custom Arrow item by deriving from QGraphicsLineItem and using a QGraphicsPolygonItem for arrow head.

    I want to use the same size for arrow head across the zoom levels so I have used flag "ItemIgnoresTransformations" but when i change the zoom value other that 1.0 then I could see that the arrow head is drawing at wrong position.

    Please see my test app below.

    const qreal Pi = 3.14;
    /// RotateHandleItem class
    class RotateHandleItem : public QGraphicsLineItem
    {
    public:
      RotateHandleItem(QGraphicsItem* parent = nullptr)
        : QGraphicsLineItem(parent),
          m_Parent(parent)
      {
        this->setAcceptHoverEvents(true);
        setFlag(ItemSendsGeometryChanges);
        setFlag(ItemIsMovable);
    
        m_ArrowHedItem = new QGraphicsPolygonItem(this);
        m_ArrowHedItem->setFlag(QGraphicsItem::ItemIgnoresTransformations);
      }
    
      QRectF boundingRect()
      {
        QRectF rect = shape().boundingRect();
        // add a few extra pixels for the arrow and the pen
        qreal penWidth = 1;
        qreal extra = (penWidth + 6) / 2.0;
        rect.adjust(-extra, -extra, extra, extra);
        return rect;
      }
      QPainterPath shape()
      {
        QPainterPath path = QGraphicsLineItem::shape();
        path.addPolygon(m_ArrowHead);
        return path;
      }
    
      void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0)
      {
        Q_UNUSED(option);
        Q_UNUSED(widget);
    
        double angle = ::acos(line().dx() / line().length());
        if (line().dy() >= 0)
          angle = (Pi * 2) - angle;
    
        QPointF arrowP1;
        QPointF arrowP2;
        qreal arrowSize = 10;
    
        m_ArrowHead.clear();
        m_ArrowHead << line().p2();
        arrowP1 = line().p2() - QPointF(sin(angle + Pi / 3) * arrowSize,
                                        cos(angle + Pi / 3) * arrowSize);
        arrowP2 = line().p2() - QPointF(sin(angle + Pi - Pi / 3) * arrowSize,
                                        cos(angle + Pi - Pi / 3) * arrowSize);
        m_ArrowHead << arrowP1 << arrowP2;
    
        QPen pen;
        pen.setWidth(1);
        pen.setCosmetic(true);
        pen.setColor(QColor(255, 204, 0));
        painter->setPen(pen);
        m_ArrowHedItem->setPen(pen);
        m_ArrowHedItem->setBrush(Qt::black);
        m_ArrowHedItem->setPolygon(m_ArrowHead);  //Arrow Head
        painter->drawLine(line());  //Arrow Line
      }
    
    private:
      QGraphicsItem* m_Parent;
      QPolygonF m_ArrowHead;
      QGraphicsPolygonItem* m_ArrowHedItem;
    };
    
    int main(int argc, char *argv[])
    {
      QApplication a(argc, argv);
    
      QGraphicsView view;
      QGraphicsScene scene;
      view.setScene(&scene);
      view.scale(2.0, 2.0);
    
      RotateHandleItem* m_RotateHandle = new RotateHandleItem();
      m_RotateHandle->setLine(100, 100, 200, 100);
      scene.addItem(m_RotateHandle);
    
      view.showMaximized();
      return a.exec();
    }
    

    In second last line of method paint() I am setting the calculated Arrow head polygon value to PolygonItem.

    I have also tried to set the polygon value after converting it using mapToParent() but didn't help. I feel like I am missing something here.

    Please help me to solve this issue.



  • You move the arrow head by changing the coordinates within the polygon itself, instead of moving the whole arrow head

    (To illustrate: Let's say your arrowhead item is a piece of paper. The polygon within is a triangle you scribble on the paper. When you want to move the triangle, you can (a) move the paper, or (b) keep the paper where it is, but scribble the triangle in a different part of the paper)

    Your RotateHandleItem is affected by the zoom. Now you use coordinates from within that object to determine the polygon for the arrow head. That way, you go over coordinate system boundaries without correctly mapping the coordinates.

    Easier way: Assign the arrow head a fixed polygon, and use the setPos method to move it to the correct position.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.