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. QGraphicsItem paints with offset (problem)
Forum Updated to NodeBB v4.3 + New Features

QGraphicsItem paints with offset (problem)

Scheduled Pinned Locked Moved General and Desktop
qgraphicsitemqgraphicsviewqt5.4
6 Posts 2 Posters 4.0k 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.
  • M Offline
    M Offline
    matejtomcik
    wrote on 16 May 2015, 18:07 last edited by
    #1

    Hi all,
    I want to create a QGraphicsView which would serve as a container for layers instead of items, each layer filling the entire scene. So I subclassed QGraphicsView and QGraphicsItem, overriden the paint event in QGraphicsItem, and resizeEvent in QGraphicsView.
    Then I configured the whole thing like this:

    • Scrolling in QGraphicsView is disabled
    • In the QGraphicsView::resizeEvent, I iterate over the QGraphicsItems, setting their bounding box to QGraphicsView::contentsRect().size() (to get rid of the QFrame borders) - the QGraphicsItem::boundingRect() simply returns QRectF(QPointF(), mContentsRectSize);
      Then I redraw the scene with invalidateScene(); and viewport()->update();
      Note that I don't call base resizeEvent()
    • The paint event in QGraphicsItem takes the bounding box whose size is equal to QGraphicsView::contentsRect().size() and draws from offset [0;0], for example: painter->fillRect(QRect(0, 0, 20, 20), Qt::red);

    Everything works fine except that there is a 1px offset from the left as well as from the top. You can see it in this image:
    http://pasteboard.co/vE1gqZB.png
    Content that extends outside of the bounding box is visible, so it means the whole QGraphicsItem is offset by 1px.

    Calling QGraphicsItem::setPos(0,0); or [-1; -1] doesn't work. The only thing that "moves" the item is setting the position to [-0.5f; -0.5f] which kind of stretches into the empty offset but only with antialiasing turned on and it only "blurs" the area, so I don't consider it a solution.

    I need to understand what is going on behind the scenes in QGraphicsView and how to fix this problem.
    Thanks.

    1 Reply Last reply
    0
    • ? Offline
      ? Offline
      A Former User
      wrote on 16 May 2015, 19:22 last edited by
      #2

      Hi,
      that's because your rectangle needs to be QRect(-penWidth/2, -penWidth/2, 20-penWidth, 20-penWidth) otherwise half of the border is drawn outside the intended area.

      M 1 Reply Last reply 16 May 2015, 19:37
      0
      • ? Offline
        ? Offline
        A Former User
        wrote on 16 May 2015, 19:25 last edited by
        #3

        ops, sorry, the minus signs are wrong. the rest is correct.

        1 Reply Last reply
        0
        • ? A Former User
          16 May 2015, 19:22

          Hi,
          that's because your rectangle needs to be QRect(-penWidth/2, -penWidth/2, 20-penWidth, 20-penWidth) otherwise half of the border is drawn outside the intended area.

          M Offline
          M Offline
          matejtomcik
          wrote on 16 May 2015, 19:37 last edited by
          #4

          @Wieland Hi, thanks for the reply, but it doesn't answer my question, also lets asume there is no antialising, working with integers only. My rectangle is defined as QRect(0, 0, 20, 20).
          I am filling the rectangle, not drawing borders. Take for example this code:

          void Layer::paint(QPainter * painter, const QStyleOptionGraphicsItem *, QWidget *)
          {
            // Size of the rectangle is taken from the parent QGraphicsView
            QRect content = QRect(QPoint(), getParentView()->contentsRect().size());
            // Simply fill the whole rectangle with color
            painter->fillRect(content, Qt::red);
          }
          

          Now one would assume that this will fill the content of the QGraphicsView with red. It does not, in my case, there is a 1px offset from the left and the top. To fill the whole view I have to do this:
          QRect content = QRect(QPoint(-1, -1), getParentView()->contentsRect().size());
          note the [-1;-1] offset

          1 Reply Last reply
          0
          • ? Offline
            ? Offline
            A Former User
            wrote on 16 May 2015, 20:53 last edited by A Former User
            #5

            @matejtomcik I can't reproduce it. Here is my code:

            #ifndef MYITEM_H
            #define MYITEM_H
            
            #include <QObject>
            #include <QGraphicsItem>
            #include <QPainter>
            #include <QWidget>
            #include <QRect>
            
            class MyItem : public QGraphicsItem
            {
            public:
                QRect parViewContRect;
            
                QRectF boundingRect() const
                {
                     return parViewContRect;
                }
            
                void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
                {
                    QPen pen(Qt::NoPen);
                    painter->setPen(pen);
                    painter->fillRect(
                                QRect(QPoint(),
                                      QSize( parViewContRect.width(), parViewContRect.height() ) )
                                , Qt::red);
                }
            };
            
            #endif // MYITEM_H
            
            MainWindow::MainWindow(QWidget *parent) :
                QMainWindow(parent),
                ui(new Ui::MainWindow)
            {
                ui->setupUi(this);
            
                QGraphicsScene *scene = new QGraphicsScene;
                ui->graphicsView->setScene(scene);
                ui->graphicsView->setAlignment( Qt::AlignLeft | Qt::AlignTop );
            
                // ui->graphicsView->setOptimizationFlag(QGraphicsView::DontAdjustForAntialiasing, true);
            
                MyItem * item = new MyItem;
                scene->addItem(item);
            
                item->parViewContRect = ui->graphicsView->contentsRect();
            }
            

            And this is what it looks like (I changed the window color to black and disabled the GraphicViews frame. The background brush of the view is white and solid): https://drive.google.com/file/d/0B2D1UtsPfTx-YkRDRThnSXRyYzA/view?usp=sharing

            M 1 Reply Last reply 17 May 2015, 08:21
            0
            • ? A Former User
              16 May 2015, 20:53

              @matejtomcik I can't reproduce it. Here is my code:

              #ifndef MYITEM_H
              #define MYITEM_H
              
              #include <QObject>
              #include <QGraphicsItem>
              #include <QPainter>
              #include <QWidget>
              #include <QRect>
              
              class MyItem : public QGraphicsItem
              {
              public:
                  QRect parViewContRect;
              
                  QRectF boundingRect() const
                  {
                       return parViewContRect;
                  }
              
                  void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
                  {
                      QPen pen(Qt::NoPen);
                      painter->setPen(pen);
                      painter->fillRect(
                                  QRect(QPoint(),
                                        QSize( parViewContRect.width(), parViewContRect.height() ) )
                                  , Qt::red);
                  }
              };
              
              #endif // MYITEM_H
              
              MainWindow::MainWindow(QWidget *parent) :
                  QMainWindow(parent),
                  ui(new Ui::MainWindow)
              {
                  ui->setupUi(this);
              
                  QGraphicsScene *scene = new QGraphicsScene;
                  ui->graphicsView->setScene(scene);
                  ui->graphicsView->setAlignment( Qt::AlignLeft | Qt::AlignTop );
              
                  // ui->graphicsView->setOptimizationFlag(QGraphicsView::DontAdjustForAntialiasing, true);
              
                  MyItem * item = new MyItem;
                  scene->addItem(item);
              
                  item->parViewContRect = ui->graphicsView->contentsRect();
              }
              

              And this is what it looks like (I changed the window color to black and disabled the GraphicViews frame. The background brush of the view is white and solid): https://drive.google.com/file/d/0B2D1UtsPfTx-YkRDRThnSXRyYzA/view?usp=sharing

              M Offline
              M Offline
              matejtomcik
              wrote on 17 May 2015, 08:21 last edited by
              #6

              @Wieland Hi, thanks for the reply, if you subclass QGraphicsView like this:

              #ifndef MYVIEW_H
              #define MYVIEW_H
              
              #include <QGraphicsView>
              #include "MyItem.h"
              
              class MyView : public QGraphicsView
              {
                  Q_OBJECT
              public:
                  inline explicit MyView(QWidget * parent = 0) :
                      QGraphicsView(parent)
                  {
                      setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
                      setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
                  }
              
              public:
                  inline virtual void resizeEvent(QResizeEvent *)
                  {
                      QSize size = contentsRect().size();
                      static_cast<MyItem *>(scene()->items().at(0))->parViewContRect = QRect(QPoint(), size);
                      invalidateScene();
                      viewport()->update();
                  }
              };
              
              #endif // MYVIEW_H
              

              Here is the result: http://pasteboard.co/wwmZHz6.png
              There is a 1px offset but on the bottom-right side.
              If you comment out this line:
              ui->graphicsView->setAlignment( Qt::AlignLeft | Qt::AlignTop );
              Then the item is offset by (in my case) 92x97 px.
              But then if I add this to the resizeEvent method:
              scene()->items().at(0)->setPos(-1, -1);
              the item will fill the whole view.

              However it doesn't solve my problem. I added this to my original code and it didn't fix the problem. But I have noticed that if I disable cache on all of my QGraphicsItems, then it works. I use
              setCacheMode(QGraphicsItem::DeviceCoordinateCache);
              on QGraphicsItem by default, then I change the bounding box like this:

              // Parameter canvasSize is equal to QGraphicsView::contentsRect().size()
              void Layer::updateViewport(const QSize & canvasSize) {
                if (cacheMode() != QGraphicsItem::NoCache)
                  prepareGeometryChange();
                mBoundingBox = QRect(QPoint(), canvasSize);
                if (cacheMode() != QGraphicsItem::NoCache)
                  update();
              }
              

              Here is the result: http://pasteboard.co/wzteGW3.png
              This happens when the cache is set to QGraphicsItem::DeviceCoordinateCache (or QGraphicsItem::ItemCoordinateCache) and I quickly resize the window. Here is a Qt project which can reproduce the error: http://matejtomcik.com/ViewProblem.zip

              1 Reply Last reply
              0

              5/6

              16 May 2015, 20:53

              • Login

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