Qt Forum

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Unsolved

    QGraphicsView render issues when scaling

    General and Desktop
    4
    17
    5853
    Loading More Posts
    • 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.
    • T
      Tectu last edited by

      I have a simple QGraphicsScene and QGraphicsView setup. So far I have never scaled or resized any of the two and everything was working perfectly.
      I draw a slider using the normal QPainter API and the result looks just fine: !http://paste.ugfx.org/sores/7505d64a54e0/0af95a019669.jpg(Slider)!

      Now I scale the scene and resize the view so it can still display the entire scene at once. I do this by using this code:
      @
      int screenWidth = 640;
      int screenHeight = 480;

      _scaleFactor = 1.0;   // This is a qreal
      
      setFixedSize(screenWidth*_scaleFactor, screenHeight*_scaleFactor);
      scale(_scaleFactor, _scaleFactor);
      fitInView(0, 0, screenWidth, screenHeight);
      

      @
      As you can see I am not really scaling it as the scale factor is 1.0. The dimensions of everything is still correct but there are now rendering issues happening:
      !http://paste.ugfx.org/sores/7505d64a54e0/291bca6a907a.jpg(slider scaled)!
      Now the green rectangle is shifted downwards by one pixel.

      For drawing the green rectangle I draw it using the following code:
      @
      QRectF greenRect = rect();
      greenRect .setX(borderPen.width());
      greenRect .setY(borderPen.width());
      greenRect .setHeight(rect().height() - borderPen.width());
      greenRect .setWidth(knobPos);
      @

      I don't really know how to address this issue. What causes this issue? I assume it's some float-to-integer rasterization. But I use QRectF everywhere.

      I experience similar issues with other items that I draw in the scene. Thins are just off by 1px in random cases and sometimes 1px width lines are missing at all.

      1 Reply Last reply Reply Quote 0
      • E
        euchkatzl last edited by

        Don't know if this is really the solution.
        But you can try to use qreal instead of int with your screen variables

        @qreal screenWidth = 640;
        qreal screenHeight = 480;@

        Using integer values will cause that in that line :
        @setFixedSize(screenWidth*_scaleFactor, screenHeight*_scaleFactor);@
        values will be casted to integer values.

        1 Reply Last reply Reply Quote 0
        • A
          Asperamanca last edited by

          Can you post your painting code?

          1 Reply Last reply Reply Quote 0
          • T
            Tectu last edited by

            @euchkatzl: I casted the values as you suggested but that didn't make the issue go away. And from my understanding they should if anything be casted to a qreal anyway as this is the type which provides more accuracy than the integer.

            @asperamanca: Here's my full paint() routine for the slider that you can see in the images above: http://paste.ugfx.org/show/3eefb77194

            1 Reply Last reply Reply Quote 0
            • R
              Rondog last edited by

              You should check the member functions (this->rect() in particular). This probably returns QRect and not QRectF. I can't tell by looking at the code.

              @
              // Create the active area rectangle
              QRectF activeRect = rect();
              activeRect.setX(rectanglePen.width());
              activeRect.setY(rectanglePen.width());
              activeRect.setHeight(rect().height() - rectanglePen.width());
              activeRect.setWidth(knobPos);
              @

              Integer rounding (or lack thereof) will cause this kind of problem.

              1 Reply Last reply Reply Quote 0
              • T
                Tectu last edited by

                Thank you very much for your suggestion. My UGfxSlider is derived from QGraphicsRectItem. QGraphicsRectItem::rect() returns a QRectF.

                I have checked the other stuff as well and everything looks fine from that point of view.

                I don't understand why this only happens after setting the scale factor etc. as shown above. The default scale factor is 1.0 and when I don't change it it is fine. But when I manually set it to 1.0 it shows the problems.

                1 Reply Last reply Reply Quote 0
                • E
                  euchkatzl last edited by

                  Could you try to use use widthF of QPen instead of width.

                  http://doc-snapshot.qt-project.org/qt5-5.4/qpen.html#widthF

                  1 Reply Last reply Reply Quote 0
                  • T
                    Tectu last edited by

                    Thank you very much for your suggestion. I have modified the code to use QPen::widthF() but the result is exactly the same.
                    @
                    QRectF activeRect = rect();
                    activeRect.setX(rectanglePen.widthF());
                    activeRect.setY(rectanglePen.widthF());
                    activeRect.setHeight(rect().height() - rectanglePen.widthF());
                    activeRect.setWidth((qreal)knobPos);
                    @
                    Any other ideas? :/

                    1 Reply Last reply Reply Quote 0
                    • E
                      euchkatzl last edited by

                      Try this in your paint and look if there are still problems. That code works for me. It a simplified version of yours without text an knob.

                      When it works as aspected you could use it to fix your code. I think there a several problems with pen width handling.

                      @painter->setRenderHint(QPainter::Antialiasing,true);
                      painter->save();
                      QPen rectanglePen;
                      rectanglePen.setColor(Qt::blue);
                      rectanglePen.setWidthF(1.0);
                      rectanglePen.setJoinStyle(Qt::MiterJoin);
                      rectanglePen.setCapStyle(Qt::FlatCap);

                      QBrush rectangleBrush;
                      rectangleBrush.setStyle(Qt::SolidPattern);
                      rectangleBrush.setColor(Qt::red);

                      painter->setPen(QPen(Qt::blue,1.0));
                      painter->setBrush(rectangleBrush);
                      painter->drawRect(rect());

                      painter->restore();

                      QRectF activeRect = rect().adjusted(rectanglePen.widthF() / 2.0,
                      rectanglePen.widthF() / 2.0,
                      -rectanglePen.widthF() / 2.0,
                      -rectanglePen.widthF() / 2.0);
                      activeRect.setWidth(30);

                      painter->fillRect(activeRect, Qt::green);@

                      1 Reply Last reply Reply Quote 0
                      • T
                        Tectu last edited by

                        I took your code and replaced my paint() routine with it. Sadly I still observe the same issues.

                        I'm really lost... Here is the full code of my QGraphicsView and QGraphicsScene derived classes:

                        mygraphicsview.h: http://paste.ugfx.org/show/e98773b84a
                        mygraphicsview.cpp: http://paste.ugfx.org/show/14e15a6d66
                        mygraphicsscene.h: http://paste.ugfx.org/show/450f49bc5e
                        mygraphicsscene.cpp: http://paste.ugfx.org/show/d5d4a8e53b

                        Now that I am pasting this, might it be related to _MyGraphicsScene::drawBackground() _?

                        Edit: I just removed my MyGraphicsScene::drawBackground() implementation and used the default one from QGraphicsScene and the issues remain.

                        1 Reply Last reply Reply Quote 0
                        • R
                          Rondog last edited by

                          I noticed in your code you have this:

                          @
                          // Actually modify the possition
                          float pos = selectedWindows.first()->y() + selectedWindows.first()->rect().height();
                          for (int i = 1; i < selectedWindows.count(); i++) {
                          pos += spaceBetweenItems;
                          selectedWindows.at(i)->setY((int)(pos + 0.5));
                          pos += selectedWindows.at(i)->rect().height();
                          }
                          @

                          This would set the Y position of each window rounded to the nearest integer value. Your screen shot shows the green rect offset from the frame by 1 pixel in the Y axis.

                          Does each object 'UGfxSlider' contain its own drawing code (dependent, i.e. upper left = 0,0) or are you drawing the position based on its calculated position (drawing independent of each item)?

                          1 Reply Last reply Reply Quote 0
                          • T
                            Tectu last edited by

                            That code is only executed when the user clicks the alignment (in this case vertical distribution) button. It is not relevant to my problem as I get the issues by just moving the item around in the scene without using any of the alignment or distribution function in MyGraphicsScene.

                            Also, please note that those functions work just fine as long as I don't execute the MyGraphicsView::updateScale(). I get the artefacts as soon as I execute that code (although my _scaleFactor is set to 1.0).

                            Each slider does contain it's own drawing code. I simply implemented the QGraphicsRectItem::paint() routine. You can see my implementation at line 133 in this file: http://paste.ugfx.org/show/ded30acd54

                            Note that I have this "off by one pixel" issue with other QGraphicsRectItem based classes too.

                            Also, the "off by one pixel" changes by moving the item across the scene. Sometimes it's right and sometimes it shows the errror. So it's definitely a rounding issue.

                            1 Reply Last reply Reply Quote 0
                            • R
                              Rondog last edited by

                              Ok. I figured it out.

                              I ran some tests on a project I have and saw the exact same thing you described using a subclass of QGraphicsItem. I didn't have anything other then two rect()'s drawn.

                              I found that by adding the following in the constructor of the QGraphicsView it solved this problem:

                              @
                              this->setRenderHints(QPainter::Antialiasing);
                              @

                              At some point in the drawing process only one pixel of the display is lit up (this is where the truncating occurs) . Antialiasing is a trick to fool your eye so that the apparent position appears somewhere between pixels.

                              1 Reply Last reply Reply Quote 0
                              • T
                                Tectu last edited by

                                I did see that the problem becomes less visible when enabling Anti-Aliasing when I tested your code. However, as you said you are still missing one of the pixel lines sometimes. This is way less visible but in my case I can't / don't want to use anti-aliasing.

                                The application I am writing is a drag'n'drop GUI designer for an embedded GUI library that targets VERY low resolution displays. If you have a resolution of just 320 x 240 pixels and a 150 x 30 pixels slider and you turn on anti-aliasing you see a big difference between the QGraphicsView rendering and the actual result (after generating the resulting code).
                                The preview that the user sees in the QGraphicsView should be as close to the actual result afterwards as possible.

                                The issue is clearly somewhere in the scaling and I hope that it can be fixed or at least workaround-ed.

                                Thank you very much for your endurance. It is appreciated a lot.

                                1 Reply Last reply Reply Quote 0
                                • R
                                  Rondog last edited by

                                  The way I did this was to draw to a QPixmap. I draw the pixmap and create or update the associated QGraphicsPixmapItem each time there is a change. I didn't even see your problem until I tested it using the QGraphicsItem.

                                  If you try the QPixmap method you would have to re-draw the QGraphicsPixmapItems when the contents or the scale changes. I don't know if this a performance hit or not. It is easier to copy the contents of a bitmap then to draw directly so it should be better from that point of view at least.

                                  Maybe separating the QGraphicsItem from the QGraphicsView might be the answer. You can use setFlag(QGraphicsItem::ItemIgnoresTransformations) to do this. You will have to manage the size and position of the control yourself but at least you have some control.

                                  I don't know. I am beginning to think this is more internal to QGraphicsView/QGraphicsScene then anything else.

                                  1 Reply Last reply Reply Quote 0
                                  • R
                                    Rondog last edited by

                                    I have one more idea. I didn't try it but it might be worth investigating.

                                    What if you limit your scale values to those that only increase the size by 1 pixel for each QGraphicItem that you have?

                                    For example, if the QGraphicItem height is 100 pixels then make sure your scale value is restricted to 1.000, 1.0100, 1.0200 and so on. Part of the problem may be that scale values that are between even pixel sizes cause something, somewhere, to shift position.

                                    You can do this independently for both axis. This assumes your QGraphicItems are not mixed sizes.

                                    1 Reply Last reply Reply Quote 0
                                    • R
                                      Rondog last edited by

                                      I have another idea.

                                      If you change the order you draw the control items this would hide the problem.

                                      • Draw the knob 'green' rect first. Don't reduce the size.
                                      • Draw the frame and other items over top.

                                      This should work without needing to add anything weird.

                                      1 Reply Last reply Reply Quote 0
                                      • First post
                                        Last post