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. QGraphicsScene: moving an item inside an item
Forum Updated to NodeBB v4.3 + New Features

QGraphicsScene: moving an item inside an item

Scheduled Pinned Locked Moved Unsolved General and Desktop
8 Posts 4 Posters 1.3k Views 2 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.
  • LeoCL Offline
    LeoCL Offline
    LeoC
    wrote on last edited by
    #1

    Hey,

    since I already have some experience using Qt, it is the first time I try using some graphic elements.

    To get a first impression how it works I watched a YouTube video. I did what he says and it works fine.
    I created a QGraphicsScene where I placed a box which is movable and as long as I click on it the colour is changed. "oneBox" inherits from QGraphicsItem.

    oneBox::oneBox()
    {
        bPressed = false;
        setFlag(ItemIsMovable);
    }
    
    QRectF oneBox::boundingRect() const
    {
        return QRectF(0,0,200,200);
    }
    
    void oneBox::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
    {
        QRectF rec = boundingRect();
    
        if(bPressed) {
            brush.setColor(Qt::red);
        }
        else {
            brush.setColor(Qt::green);
        }
    
        painter->fillRect(rec,brush);
        painter->drawRect(rec);
    }
    
    void oneBox::mousePressEvent(QGraphicsSceneMouseEvent *event)
    {
        bPressed = true;
        update();
        QGraphicsItem::mousePressEvent(event);
    }
    
    void oneBox::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
    {
        bPressed = false;
        update();
        QGraphicsItem::mouseReleaseEvent(event);
    }
    

    Now, what I want to have is a horizontal line that divides this box in an upper and a lower part. The user can move the line up and down in order the change the size of the upper and the lower part. So, the line should be movable but only in y - direction. The lower part should have another colour than the upper one.

    I guess I need a qgraphicslineitem. But I am not sure where to place it.
    When I create a new class which lives parallel to "oneBox" I could add the line to the same scene as the "oneBox". But then I can move the line also outside of the box. That should not be the case.
    Then I thought I could create a new QGraphicsScene inside "oneBox" which has the same size as the boundingRect. In this case the line would be only movable inside the "oneBox". But I am not sure if the new GraphicsScene then lies on top of the "oneBox" so I cannot grab the "oneBox" anymore to move it around.

    I really hope you got what I mean and you can tell me what I have to do.

    Cheers
    Chris

    JonBJ Pl45m4P 2 Replies Last reply
    0
    • LeoCL LeoC

      Hey,

      since I already have some experience using Qt, it is the first time I try using some graphic elements.

      To get a first impression how it works I watched a YouTube video. I did what he says and it works fine.
      I created a QGraphicsScene where I placed a box which is movable and as long as I click on it the colour is changed. "oneBox" inherits from QGraphicsItem.

      oneBox::oneBox()
      {
          bPressed = false;
          setFlag(ItemIsMovable);
      }
      
      QRectF oneBox::boundingRect() const
      {
          return QRectF(0,0,200,200);
      }
      
      void oneBox::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
      {
          QRectF rec = boundingRect();
      
          if(bPressed) {
              brush.setColor(Qt::red);
          }
          else {
              brush.setColor(Qt::green);
          }
      
          painter->fillRect(rec,brush);
          painter->drawRect(rec);
      }
      
      void oneBox::mousePressEvent(QGraphicsSceneMouseEvent *event)
      {
          bPressed = true;
          update();
          QGraphicsItem::mousePressEvent(event);
      }
      
      void oneBox::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
      {
          bPressed = false;
          update();
          QGraphicsItem::mouseReleaseEvent(event);
      }
      

      Now, what I want to have is a horizontal line that divides this box in an upper and a lower part. The user can move the line up and down in order the change the size of the upper and the lower part. So, the line should be movable but only in y - direction. The lower part should have another colour than the upper one.

      I guess I need a qgraphicslineitem. But I am not sure where to place it.
      When I create a new class which lives parallel to "oneBox" I could add the line to the same scene as the "oneBox". But then I can move the line also outside of the box. That should not be the case.
      Then I thought I could create a new QGraphicsScene inside "oneBox" which has the same size as the boundingRect. In this case the line would be only movable inside the "oneBox". But I am not sure if the new GraphicsScene then lies on top of the "oneBox" so I cannot grab the "oneBox" anymore to move it around.

      I really hope you got what I mean and you can tell me what I have to do.

      Cheers
      Chris

      JonBJ Offline
      JonBJ Offline
      JonB
      wrote on last edited by
      #2

      @LeoC
      I don't think you want anything like "multiple graphics scenes". I'm not sure whether an extra graphics item is the best way to do your dividing line, someone will probably tell you to do it in drawing the box item. But if you do want to do it via a separate item, did you try making that line a child of the box item? This is only a guess, but I would have thought that would be how you would do one graphics item living on top of another?

      1 Reply Last reply
      1
      • LeoCL LeoC

        Hey,

        since I already have some experience using Qt, it is the first time I try using some graphic elements.

        To get a first impression how it works I watched a YouTube video. I did what he says and it works fine.
        I created a QGraphicsScene where I placed a box which is movable and as long as I click on it the colour is changed. "oneBox" inherits from QGraphicsItem.

        oneBox::oneBox()
        {
            bPressed = false;
            setFlag(ItemIsMovable);
        }
        
        QRectF oneBox::boundingRect() const
        {
            return QRectF(0,0,200,200);
        }
        
        void oneBox::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
        {
            QRectF rec = boundingRect();
        
            if(bPressed) {
                brush.setColor(Qt::red);
            }
            else {
                brush.setColor(Qt::green);
            }
        
            painter->fillRect(rec,brush);
            painter->drawRect(rec);
        }
        
        void oneBox::mousePressEvent(QGraphicsSceneMouseEvent *event)
        {
            bPressed = true;
            update();
            QGraphicsItem::mousePressEvent(event);
        }
        
        void oneBox::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
        {
            bPressed = false;
            update();
            QGraphicsItem::mouseReleaseEvent(event);
        }
        

        Now, what I want to have is a horizontal line that divides this box in an upper and a lower part. The user can move the line up and down in order the change the size of the upper and the lower part. So, the line should be movable but only in y - direction. The lower part should have another colour than the upper one.

        I guess I need a qgraphicslineitem. But I am not sure where to place it.
        When I create a new class which lives parallel to "oneBox" I could add the line to the same scene as the "oneBox". But then I can move the line also outside of the box. That should not be the case.
        Then I thought I could create a new QGraphicsScene inside "oneBox" which has the same size as the boundingRect. In this case the line would be only movable inside the "oneBox". But I am not sure if the new GraphicsScene then lies on top of the "oneBox" so I cannot grab the "oneBox" anymore to move it around.

        I really hope you got what I mean and you can tell me what I have to do.

        Cheers
        Chris

        Pl45m4P Offline
        Pl45m4P Offline
        Pl45m4
        wrote on last edited by Pl45m4
        #3

        @LeoC

        The short form is:

        • create a line item (QGraphicsLineItem)
        • add it to your box (box becomes parent) and make it moveable.
        • control the movement and the position to re-paint the box below and above that line

        I can give you an example later. Just try it yourself first, based on this information :)


        If debugging is the process of removing software bugs, then programming must be the process of putting them in.

        ~E. W. Dijkstra

        1 Reply Last reply
        2
        • M Offline
          M Offline
          mchinand
          wrote on last edited by
          #4

          In addition to what Pl45m4 outlined, you may need to reimplement the itemChange() method to limit the movement of the line to horizontal movements.

          1 Reply Last reply
          1
          • Pl45m4P Offline
            Pl45m4P Offline
            Pl45m4
            wrote on last edited by Pl45m4
            #5

            I didnt limit the movement of the handle in X-direction but that should not be a problem to add later.

            BoxHandle.gif

            #ifndef BOXHANDLE_H
            #define BOXHANDLE_H
            
            #include <QGraphicsLineItem>
            
            class BoxHandle: public QGraphicsLineItem
            {
            public:
            
                BoxHandle();
                BoxHandle(qreal x1, qreal y1, qreal x2, qreal y2, QGraphicsItem *parent = nullptr);
            
            protected:
            
                void mousePressEvent(QGraphicsSceneMouseEvent *event);
                void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
                void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
            
            };
            
            #endif // BOXHANDLE_H
            
            
            #include "boxhandle.h"
            
            #include <QDebug>
            #include <QPen>
            BoxHandle::BoxHandle():
                QGraphicsLineItem()
            {}
            
            BoxHandle::BoxHandle(qreal x1, qreal y1, qreal x2, qreal y2, QGraphicsItem *parent):
                QGraphicsLineItem(x1, y1, x2, y2, parent)
            {
                setFlag(ItemIsMovable);
                QPen pen(Qt::red, 5);
                setPen(pen);
            }
            
            void BoxHandle::mousePressEvent(QGraphicsSceneMouseEvent *event)
            {
                QGraphicsItem::mousePressEvent(event);
            }
            
            void BoxHandle::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
            {
                QGraphicsItem::mouseReleaseEvent(event);
            }
            
            void BoxHandle::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
            {
                QGraphicsItem::mouseMoveEvent(event);
            }
            
            
            #ifndef MYBOX_H
            #define MYBOX_H
            #include <QGraphicsItem>
            #include <boxhandle.h>
            
            class MyBox: public QGraphicsItem
            {
            public:
                MyBox();
            
                QRectF boundingRect() const;
            
                void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
            
            protected:
            
                void mousePressEvent(QGraphicsSceneMouseEvent *event);
                void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
            
            
            private:
            
                bool pressed;
                BoxHandle *handle;
            };
            
            #endif // MYBOX_H
            
            #include "mybox.h"
            #include <QBrush>
            #include <QPainter>
            #include <QDebug>
            #include <QGraphicsSceneMouseEvent>
            
            MyBox::MyBox():
                QGraphicsItem(), pressed(false), handle(new BoxHandle(0, 0, 200, 0, this))
              // HandleSize = BoxWidth, probably requires some adjustment later
            {
                setFlag(ItemIsMovable);
            }
            
            QRectF MyBox::boundingRect() const
            {
                return QRectF(0, 0, 200, 200);
            }
            
            void MyBox::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
            {
                QRectF rec = boundingRect();
            
                // Get Handle Pos
                qreal handlePosY = handle->mapToParent(0, 0).y();
            
                // Rect below handle
                QRectF below = QRectF(0, handlePosY, boundingRect().width(), boundingRect().height() - handlePosY);
            
            
                painter->fillRect(below, Qt::green);
            
                // Rect above handle
                QRectF above = QRectF(0, 0, boundingRect().width(), boundingRect().height() - (boundingRect().height() - handlePosY));
            
            
                painter->fillRect(above, Qt::blue);
                painter->drawRect(rec);
            }
            
            void MyBox::mousePressEvent(QGraphicsSceneMouseEvent *event)
            {
                pressed = true;
                update();
                QGraphicsItem::mousePressEvent(event);
            }
            
            void MyBox::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
            {
                pressed = false;
                update();
                QGraphicsItem::mouseReleaseEvent(event);
            }
            
            

            Also I skipped the itemChange part... Dont want to do all of your work :)
            And there are probably better solutions than doing all the stuff in paint event (I guess?!)

            Btw: The "artifacts" near the border of the box are not really there. They are only visible in the recorded gif.


            If debugging is the process of removing software bugs, then programming must be the process of putting them in.

            ~E. W. Dijkstra

            1 Reply Last reply
            4
            • LeoCL Offline
              LeoCL Offline
              LeoC
              wrote on last edited by
              #6

              @Pl45m4 thanks!

              Your little animation is exactly what I wanted to achieve.
              Unfortunately I couldn't try it by myself so far but I will do as soon as I can.

              1 Reply Last reply
              0
              • LeoCL Offline
                LeoCL Offline
                LeoC
                wrote on last edited by
                #7

                @Pl45m4 now I implemented everything as you suggested and it works. Thank you for your support. It would have took me days to figure this out.

                I also added the following to BoxHandle

                void oneBoxHandle::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
                {
                    QGraphicsItem::mouseMoveEvent(event);
                
                    setPos(0, y());
                
                    if(y() < 0)
                        setPos(x(),0);
                    if(y() > rectY)
                        setPos(x(),rectY);
                }
                

                and now the red line only moves in y direction inside the box.

                So in the end it looks like it should. Now I can create everything else around it.

                btw: the artifacts are also visible on my screen. So it is not a matter of the gif :)

                Pl45m4P 1 Reply Last reply
                0
                • LeoCL LeoC

                  @Pl45m4 now I implemented everything as you suggested and it works. Thank you for your support. It would have took me days to figure this out.

                  I also added the following to BoxHandle

                  void oneBoxHandle::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
                  {
                      QGraphicsItem::mouseMoveEvent(event);
                  
                      setPos(0, y());
                  
                      if(y() < 0)
                          setPos(x(),0);
                      if(y() > rectY)
                          setPos(x(),rectY);
                  }
                  

                  and now the red line only moves in y direction inside the box.

                  So in the end it looks like it should. Now I can create everything else around it.

                  btw: the artifacts are also visible on my screen. So it is not a matter of the gif :)

                  Pl45m4P Offline
                  Pl45m4P Offline
                  Pl45m4
                  wrote on last edited by
                  #8

                  @LeoC said in QGraphicsScene: moving an item inside an item:

                  So it is not a matter of the gif :)

                  They were not visible when I ran the program. Only after recording.


                  If debugging is the process of removing software bugs, then programming must be the process of putting them in.

                  ~E. W. Dijkstra

                  1 Reply Last reply
                  0

                  • Login

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