Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Code to create a Arrow graphics Item in Qt
Forum Updated to NodeBB v4.3 + New Features

Code to create a Arrow graphics Item in Qt

Scheduled Pinned Locked Moved General and Desktop
15 Posts 4 Posters 19.6k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • J Offline
    J Offline
    jeevan_reddy
    wrote on 12 Mar 2014, 18:10 last edited by
    #1

    Hi All,

    I need to create Arrow graphics Item in Qt.I believe it should be a subclass of QGraphicsLineItem. Can somebody please help me with the code for Arrow creation?

    My requirement is that I am currently working on a QGraphicsScene on which I drop a QGraphicsLineItem from another scene. My Arrow item should be displayed perpendicular to the QGraphicsLineItem on the graphics scene.
    The Arrow item should be able to displayed on either side of the line item.

    1 Reply Last reply
    0
    • B Offline
      B Offline
      belab
      wrote on 12 Mar 2014, 20:18 last edited by
      #2

      Hi jeevan,

      you could use "QGraphicsSvgItem ...":http://qt-project.org/doc/qt-5/qgraphicssvgitem.html e.g.
      @
      item = new QGraphicsSvgItem(":/arrow.svg");
      @

      and use svg edit or inkscape to create arrow.svg.

      1 Reply Last reply
      0
      • J Offline
        J Offline
        jeevan_reddy
        wrote on 13 Mar 2014, 05:51 last edited by
        #3

        @Bela - Thanks bela. My requirement is that I am currently working on a QGraphicsScene on which I drop a QGraphicsLineItem from another scene. My Arrow item should be displayed perpendicular to the QGraphicsLineItem on the graphics scene.

        So My question is will QGraphicsSvgItem suit my requirement? I am very new to graphics concepts.

        1 Reply Last reply
        0
        • A Offline
          A Offline
          Asperamanca
          wrote on 13 Mar 2014, 11:23 last edited by
          #4

          I believe QGraphicsPathItem is better suited. You can either draw the whole arrow using a QPainterPath, or you can just use it to create an arrow head, and use it together with QGraphicsLineItem to make an arrow.

          1 Reply Last reply
          0
          • J Offline
            J Offline
            jeevan_reddy
            wrote on 13 Mar 2014, 13:54 last edited by
            #5

            @Asperamanca - Thanks Asper. Could you please demonstrate using the sample code for my understanding since I am new to Graphics. My requirement is to display an Arrow perpendicular to a QGraphicsLineItem, whenever a QGraphicsLineItem is dropped onto a QGraphicsScene.

            Basically once the Line item is dropped on to the scene, the Arrow item should appear perpendicular to the line item at any position above the line item.

            1 Reply Last reply
            0
            • A Offline
              A Offline
              Asperamanca
              wrote on 13 Mar 2014, 16:29 last edited by
              #6
              • Get the QLineF from the QGraphicsLineItem using line()
              • Use QLineF::normalVector() to get a perpendicular line
              • Create a QPainterPath
              • Use addPolygon to add your arrow shape. In the simplest case, it might be just a triangle consisting of the endpoint of your normalVector, and two points on the line you originally got from the QGraphicsLineItem
              • Create a QGraphicsPathItem and feed it the path (setPath)
              • Position it where you want it
              1 Reply Last reply
              0
              • K Offline
                K Offline
                karim24
                wrote on 13 Mar 2014, 22:55 last edited by
                #7

                you should check diagram scene example there is a class called Arrow
                "link":http://qt-project.org/doc/qt-4.8/graphicsview-diagramscene.html

                1 Reply Last reply
                0
                • J Offline
                  J Offline
                  jeevan_reddy
                  wrote on 15 Mar 2014, 14:17 last edited by
                  #8

                  @karim24 - Thank you very much for pointing the Arrow example to me. It was really helpful although I do not understand the algorithm for rendering the triangle portion of the Arrow item. But I am able to create arrow.

                  1 Reply Last reply
                  0
                  • J Offline
                    J Offline
                    jeevan_reddy
                    wrote on 16 Mar 2014, 18:13 last edited by
                    #9

                    @Asperamanca - Hi, I tried writing the code and this is how it is, the code is inspired by the diagram scene example of Qt.

                    @QPainterPath CustomGraphicsArrow::shape()

                    const
                    {

                    QPainterPath path = QGraphicsLineItem::shape();

                    path.addPolygon(arrowHead);

                    return path;
                    }

                    void

                    CustomGraphicsArrow::paint(QPainter *painter, const QStyleOptionGraphicsItem *,
                    QWidget *)

                    {

                    QPen myPen = pen();

                    myPen.setColor(myColor);

                    qreal arrowSize = 10;

                    painter->setPen(myPen);

                    painter->setBrush(myColor);

                    QGraphicsLineItem *parent_line_item =

                    dynamic_cast<QGraphicsLineItem *>(parent_graphics_item);
                    QLineF normal_vector_line;

                    QLineF parent_line;

                    if(parent_line_item)
                    {
                    parent_line = parent_line_item->line();
                    normal_vector_line = parent_line.normalVector();
                    }

                    qDebug() <<"The normal vector line point P1" << normal_vector_line.p1();
                    qDebug() <<"The normal vector line point P2" << normal_vector_line.p2();

                    normal_vector_line.setLength(40.0);
                    setLine(normal_vector_line);

                    // QLineF arrow_line = this->line();
                    // arrow_line.setLength(35.0);
                    double angle = ::acos(line().dx() / line().length());
                    if (line().dy() >= 0)
                    {

                    angle = (Pi * 2) - angle;

                    }

                    QPointF arrowP1 = line().p2() - QPointF(sin(angle + Pi / 3) * arrowSize,
                    cos(angle + Pi / 3) * arrowSize);

                    QPointF arrowP2 = line().p2() - QPointF(sin(angle + Pi - Pi / 3) * arrowSize,
                    cos(angle + Pi - Pi / 3) * arrowSize);

                    arrowHead.clear();
                    arrowHead << arrowP1 << arrowP2 << line().p2();
                    painter->drawLine(line());
                    painter->drawPolygon(arrowHead);

                    }@

                    In the paint(), the direction of the arrow (upwards/downwards) can be
                    determined by chaging the arrowP1, arrowP2 values.In the sample code above the arrow is displayed in the upward direction. If the arrow needs to be displayed in downward direction :

                    QPointF arrowP1 = line().p1() + QPointF(sin(angle + Pi / 3) * arrowSize,
                    cos(angle + Pi / 3) * arrowSize);

                    QPointF arrowP2 = line().p1() + QPointF(sin(angle + Pi - Pi / 3) * arrowSize,
                    cos(angle + Pi - Pi / 3) * arrowSize);

                    1 Reply Last reply
                    0
                    • J Offline
                      J Offline
                      jeevan_reddy
                      wrote on 16 Mar 2014, 18:21 last edited by
                      #10

                      @Asperamanca - I did not understand your below lines in the explanantion:

                      bq. Use addPolygon to add your arrow shape. In the simplest case, it might be just a triangle consisting of the endpoint of your normalVector, and two points on the line you originally got from the QGraphicsLineItem

                      I believe ine end point of triangle will be the end point of normal vector but the other two points of triangle will never be on the line which I got from QGrpahicsLineItem.

                      My big challenge in your code explanation comes from the fact that how do we determine the other two points of the triangle apart from the one which is the end point of normal vector?

                      1 Reply Last reply
                      0
                      • A Offline
                        A Offline
                        Asperamanca
                        wrote on 17 Mar 2014, 08:01 last edited by
                        #11

                        QLineF offers a few helpful methods.
                        You can use pointAt to get any point along the line, e.g. pointAt(0.5) would be the middle of the line. If you say you want your arrow centered on the line, you could get the required points for the triangle by using:

                        @QPointF pt1 = line.pointAt((0.4);
                        QPointF pt2 = line.pointAt((0.6);@

                        However, now the width of the triangle would depend on the width of the line. You can correct this by starting from the middle:
                        @QPointF ptMiddle = line.pointAt(0.5); // line is the line you got from the QGraphicsLineItem - the base line for your triangle
                        QLineF lineAdd;
                        lineAdd.setP1(ptMiddle); // Start from the middle
                        lineAdd.setLength(3.0); // Length for half the width of the triangle
                        lineAdd.setAngle(line.angle()); // Bring to same direction as line
                        QPointF pt1 = lineAdd.p2(); //pt1 is now exactly 3 pixels along the base line of the triangle
                        // Do the same thing in the other direction
                        lineAdd.setAngle(lineAdd.angle() - 180.0)
                        QPointF pt2 = lineAdd.p2(); //pt2 is now exactly 3 pixels along the base line, but in the other direction@

                        1 Reply Last reply
                        0
                        • J Offline
                          J Offline
                          jeevan_reddy
                          wrote on 17 Mar 2014, 19:05 last edited by
                          #12

                          @Asperamanca - . I am able to display the arrow item perpendicular to the dropped QGraphicsLineItem on the scene. The Arrow item used itself is a custom Arrow which is derived from QGraphicsLineItem. The issue I am facing now is that, the Arrow item should not only be perpendicular to the dropped line item but should also intersect the line item at some point. this gives the impression of direction flow from one side to other.

                          since I used normal vector as reference to display the starting point of arrow item (point P1), I am unable to position it in such a way that it intersects the line item. I tried doing it using some random transformation after first moving the Point P1 to middle of parent line item. But the whole thing blows away once I start rotating the line item. The intent is to see that Arrow item remains in the same position and at same angle(90 degrees) when the parent line item starts rotating. Currently the Arrow item remains at 90 degrees but the position gets displaced as we rotate the line item. how do we fix this issue?

                          Please find my current code below:

                          @QPainterPath CustomGraphicsArrow::shape() const
                          {

                          QPainterPath path = QGraphicsLineItem::shape();
                           path.addPolygon(arrowHead);
                          return path;
                          

                          }

                          void CustomGraphicsArrow::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
                          {

                          QPen myPen = pen();
                          myPen.setColor(myColor);
                          qreal arrowSize = 10;
                          painter->setPen(myPen);
                          painter->setBrush(myColor);

                          QGraphicsLineItem *parent_line_item = dynamic_cast<QGraphicsLineItem *>(parent_graphics_item);
                          QLineF normal_vector_line;

                          QLineF parent_line;
                          if(parent_line_item)
                          {

                            parent_line = parent_line_item->line();
                            normal_vector_line = parent_line.normalVector();
                          

                          }

                          QPointF parent_mid_point = parent_line.pointAt(0.5);

                          QPointF arrow_line_start_point = this->mapFromParent(parent_mid_point);
                           normal_vector_line.setLength(50.0);
                          
                          setLine(normal_vector_line);
                          QLineF arrow_line = line();
                          

                          QPointF translate_point = QPointF(-5.0, arrow_line_start_point.y());

                          arrow_line.translate(translate_point);

                          double angle = ::acos(line().dx() / line().length());
                          if (line().dy() >= 0)
                          {
                          angle = (Pi * 2) - angle;
                          }

                          QPointF arrowP1 = arrow_line.p2() - QPointF(sin(angle + Pi / 3) * arrowSize,
                          

                          cos(angle + Pi / 3) * arrowSize);
                          QPointF arrowP2 = arrow_line.p2() - QPointF(sin(angle + Pi - Pi / 3) * arrowSize,
                          cos(angle + Pi - Pi / 3) * arrowSize);

                           arrowHead.clear();
                           arrowHead << arrowP1 << arrowP2 << arrow_line.p2();
                           painter->drawLine(arrow_line);
                           painter->drawPolygon(arrowHead);
                          

                          }@

                          [QUOTE]Basically, how do i position an arrow item such that it intersects the dropped line item and when the line item is rotated, the Arrow item maintains its position and angle too? Could you please suggest me a solution to the issue? [/QUOTE]

                          1 Reply Last reply
                          0
                          • A Offline
                            A Offline
                            Asperamanca
                            wrote on 18 Mar 2014, 07:09 last edited by
                            #13

                            You can probably make your life easier by using the boundingRect to your advantage. Note that a boundingRect is a QRectF, not a QSizeF. It has a position as well as a size.
                            The position you assign to an item using setPos corresponds to the 0/0-Position on your boundingRect. So, e.g. when your boundingRect is -10/-10 to 10/10, setPos will work with the center point of your item. That should make rotation much easier.

                            1 Reply Last reply
                            0
                            • J Offline
                              J Offline
                              jeevan_reddy
                              wrote on 18 Mar 2014, 08:15 last edited by
                              #14

                              I do have a bounding rect for my arrow item :

                              @QRectF CustomGraphicsArrow::boundingRect() const
                              {
                              qreal extra = (pen().width() + 20) / 2.0;

                              return QRectF(line().p1(), QSizeF(line().p2().x() - line().p1().x(),
                                                                line().p2().y() - line().p1().y()))
                                  .normalized()
                                  .adjusted(-extra, -extra, extra, extra);
                              

                              }@

                              I'm not sure how having a bounding rect for my arrow item helps me in rotation. I'm not sure if you got the picture of the problem I am facing:

                              I have a parent QGraphicsLineItem, which is dropped on to a scene. This parent item can rotated and resized. Once the parent line item is drooped on to the scene, the Arrow line item should appear perpendicular to the parent line item and it should be positioned in such a way that, the arrow item should intercept the parent item. The arrow item should not have the same P1 as the normal vector, it should be positioned as if it is intercepting the parent line.
                              I managed to do that by giving the arrow item coordinates
                              QPointF translate_point = QPointF(-5.0, arrow_line_start_point.y());

                              I called translate on arrow line item with above coordinates.

                              I believe this will translate the Arrow's P1 from (0,0) to the specified
                              postion. Note : I haven't used any setPos() at all.

                              Now when I rotate the parent line item the Arrow item position keeps changing but I want it to remain static at all the time. The arrow should also rotate along with the parent line item. How do I achieve this?

                              1 Reply Last reply
                              0
                              • A Offline
                                A Offline
                                Asperamanca
                                wrote on 18 Mar 2014, 15:17 last edited by
                                #15

                                I am sorry, but I do not have time to think about your problem in depth. My gut feeling is that the "translate" is hurting you, as it moves the axis around which your item must rotate.

                                Try to modify the boundingRect of your arrow item in such a way that the item's position is equal to the rotation axis, i.e. on the intersection point with your parent line (the way I understand your problem).

                                1 Reply Last reply
                                0

                                1/15

                                12 Mar 2014, 18:10

                                • Login

                                • Login or register to search.
                                1 out of 15
                                • First post
                                  1/15
                                  Last post
                                0
                                • Categories
                                • Recent
                                • Tags
                                • Popular
                                • Users
                                • Groups
                                • Search
                                • Get Qt Extensions
                                • Unsolved