Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. Rendering error after changing the size of Window
QtWS25 Last Chance

Rendering error after changing the size of Window

Scheduled Pinned Locked Moved Unsolved QML and Qt Quick
windowimage
4 Posts 2 Posters 1.3k Views
  • 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.
  • W Offline
    W Offline
    wangfys
    wrote on last edited by
    #1

    I'm trying to implement a simple image viewer. I hope the image viewer can show the image without scaling, so I read the documentation about Image and find that I can use sourceSize property to get the real size. But there is something wrong after I change the size of Window to fit the size of the image.
    I use a FileDialog to choose a file and dynamiclly create a new Window to show the image.

    FileDialog {
            id: fileDialog
            title: "Choose a file"
            folder: shortcuts.home
            onAccepted: {
                var image = Qt.createComponent("qrc:/image.qml").createObject(appWindow, {});
                image.data[1].source = this.fileUrl;
            }
    }
    

    And this is my image.qml

    import QtQuick 2.11
    import QtQuick.Window 2.11
    import QtQuick.Controls 1.4
    Window {
        id: imageWindow
        visible: true
        width: 200
        height: 200
        ToolBar {
            height: 50
            Row {
                ToolButton {
                    width: 70
                    height: 45
                    text: qsTr("Exit")
                    onClicked: imageWindow.close()
                }
            }
        }
        Image {
            id: showImage
            y: 50
            onSourceSizeChanged: {
                imageWindow.height = this.sourceSize.height + 50;
                imageWindow.width = this.sourceSize.width;
            }
        }
    }
    

    I tried to change the Window's size when receiving sourceChanged signal, but failed because at that time, sourceSize is still (0, 0). So I choose to change the Window's size when receiving sourceSizeChanged signal.

    This image for test is 256*256:
    0_1534609620073_warp_test.png
    And I get a result like this:
    0_1534609719534_无标题.png

    There is an empty hole that looks like 200*200. After I drag the edge of the window it becomes normal immediately.
    0_1534609857041_无标题1.png

    So what's wrong with this process?

    DiracsbracketD 1 Reply Last reply
    0
    • W wangfys

      I'm trying to implement a simple image viewer. I hope the image viewer can show the image without scaling, so I read the documentation about Image and find that I can use sourceSize property to get the real size. But there is something wrong after I change the size of Window to fit the size of the image.
      I use a FileDialog to choose a file and dynamiclly create a new Window to show the image.

      FileDialog {
              id: fileDialog
              title: "Choose a file"
              folder: shortcuts.home
              onAccepted: {
                  var image = Qt.createComponent("qrc:/image.qml").createObject(appWindow, {});
                  image.data[1].source = this.fileUrl;
              }
      }
      

      And this is my image.qml

      import QtQuick 2.11
      import QtQuick.Window 2.11
      import QtQuick.Controls 1.4
      Window {
          id: imageWindow
          visible: true
          width: 200
          height: 200
          ToolBar {
              height: 50
              Row {
                  ToolButton {
                      width: 70
                      height: 45
                      text: qsTr("Exit")
                      onClicked: imageWindow.close()
                  }
              }
          }
          Image {
              id: showImage
              y: 50
              onSourceSizeChanged: {
                  imageWindow.height = this.sourceSize.height + 50;
                  imageWindow.width = this.sourceSize.width;
              }
          }
      }
      

      I tried to change the Window's size when receiving sourceChanged signal, but failed because at that time, sourceSize is still (0, 0). So I choose to change the Window's size when receiving sourceSizeChanged signal.

      This image for test is 256*256:
      0_1534609620073_warp_test.png
      And I get a result like this:
      0_1534609719534_无标题.png

      There is an empty hole that looks like 200*200. After I drag the edge of the window it becomes normal immediately.
      0_1534609857041_无标题1.png

      So what's wrong with this process?

      DiracsbracketD Offline
      DiracsbracketD Offline
      Diracsbracket
      wrote on last edited by Diracsbracket
      #2

      @wangfys
      Really strange indeed. I tested your code, and it is perfectly working, for any images I use, including yours. I tested on Win10, Qt 5.11.0. Using onSourceChanged instead does indeed not work.

      Aside from not being very useful here, why not writing something like

      Window {
          id: imageWindow
          ...
          property alias showImage: showImage
          ...
          Image {
               id: showImage
               ...
          }
      

      and then use

      image.showImage.source = this.fileUrl;
      

      instead of

      image.data[1].source = this.fileUrl;
      
      1 Reply Last reply
      0
      • W Offline
        W Offline
        wangfys
        wrote on last edited by wangfys
        #3

        @Diracsbracket Thanks for the suggestion!

        I find this problem only occurs when opening the first image.
        strange
        It's very confusing.

        And I try to avoid the problem by setting the Window invisible at first and then setting it visible after source is set.
        But I face another problem now. I add a feature for my program. I want to draw something. (In fact I'm doing a homework about image warping. I need to set some control points)

        Here is the effect:
        0_1534669584548_a.gif
        I draw some lines but nothing is showed.
        Then I pressed Exit button and keep pressed while exiting the button area so the button won't get a clicked signal and the Window won't close.

        Now everything works fine. Maybe there's something wrong that the program can't refresh or update rendering automatically at first.

        I implemented the drawing function according to the document about Scene Graph - Custom Geometry

        Here is my new version of image.qml

        import QtQuick 2.11
        import QtQuick.Window 2.11
        import QtQuick.Controls 1.4
        
        import CustomItem 1.0
        
        Window {
            id: imageWindow
            visible: false
            width: 200
            height: 200
            property alias showImage: showImage
            ToolBar {
                height: 50
                Row {
                    ToolButton {
                        width: 70
                        height: 45
                        text: qsTr("Exit")
                        onClicked: imageWindow.close()
                    }
                }
            }
            Image {
                id: showImage
                y: 50
                onSourceSizeChanged: {
                    imageWindow.height = this.sourceSize.height + 50;
                    imageWindow.width = this.sourceSize.width;
                    mouse.height = this.sourceSize.height;
                    mouse.width = this.sourceSize.width;
                    canvas.height = this.sourceSize.height;
                    canvas.width = this.sourceSize.width;
                }
            }
            MouseArea {
                id: mouse
                y: 50
                hoverEnabled: true
                property bool draw: false
                onPressed: {
                    draw = true;
                    points.addPoint(Qt.point(this.mouseX, this.mouseY));
                    points.addPoint(Qt.point(this.mouseX, this.mouseY));
                }
                onPositionChanged: {
                    if (draw === true)
                    {
                        points.setCurrentPoint(Qt.point(this.mouseX, this.mouseY));
                    }
                }
                onReleased: draw = false;
            }
            Rectangle {
                id: canvas
                y: 50
                color: "transparent"
                MyPointPairs {
                    id: points
                }
            }
        }
        

        I use qmlRegisterType<pointpairs>("CustomItem", 1, 0, "MyPointPairs"); in main.cpp to register pointpairs and here is my pointpairs.h

        #ifndef POINTPAIRS_H
        #define POINTPAIRS_H
        
        #include <QQuickItem>
        
        class pointpairs: public QQuickItem
        {
            Q_OBJECT
        public:
            pointpairs(QQuickItem *parent=nullptr);
            ~pointpairs();
        
            QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *);
        
        public slots:
            void addPoint(const QPointF &p);
            void setCurrentPoint(const QPointF &p);
        
        private:
            QVariantList points;
        };
        
        #endif // CLIENT_H
        

        and pointpairs.cpp

        #include "pointpairs.h"
        
        #include <QSGNode>
        #include <QSGFlatColorMaterial>
        
        pointpairs::pointpairs(QQuickItem *parent)
            : QQuickItem(parent)
        {
            setFlag(ItemHasContents, true);
        }
        
        pointpairs::~pointpairs()
        {
        }
        
        QSGNode *pointpairs::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
        {
            QSGGeometryNode *node = nullptr;
            QSGGeometry *geometry = nullptr;
        
            if (!oldNode)
            {
                node = new QSGGeometryNode;
                geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), points.count());
                geometry->setLineWidth(20);
                geometry->setDrawingMode(QSGGeometry::DrawLines);
                node->setGeometry(geometry);
                node->setFlag(QSGNode::OwnsGeometry);
                QSGFlatColorMaterial *material = new QSGFlatColorMaterial;
                material->setColor(QColor(255, 165, 0));
                node->setMaterial(material);
                node->setFlag(QSGNode::OwnsMaterial);
            }
            else
            {
                node = static_cast<QSGGeometryNode *>(oldNode);
                geometry = node->geometry();
                geometry->allocate(points.count());
            }
            QSGGeometry::Point2D *vertices = geometry->vertexDataAsPoint2D();
            for (int i=0; i<points.count(); ++i)
            {
                vertices[i].set(points[i].toPointF().x(), points[i].toPointF().y());
            }
            node->markDirty(QSGNode::DirtyGeometry);
            return node;
        }
        
        void pointpairs::addPoint(const QPointF &p)
        {
            points << p;
            update();
        }
        
        void pointpairs::setCurrentPoint(const QPointF &p)
        {
            points[points.count() - 1] = p;
            update();
        }
        
        DiracsbracketD 1 Reply Last reply
        0
        • W wangfys

          @Diracsbracket Thanks for the suggestion!

          I find this problem only occurs when opening the first image.
          strange
          It's very confusing.

          And I try to avoid the problem by setting the Window invisible at first and then setting it visible after source is set.
          But I face another problem now. I add a feature for my program. I want to draw something. (In fact I'm doing a homework about image warping. I need to set some control points)

          Here is the effect:
          0_1534669584548_a.gif
          I draw some lines but nothing is showed.
          Then I pressed Exit button and keep pressed while exiting the button area so the button won't get a clicked signal and the Window won't close.

          Now everything works fine. Maybe there's something wrong that the program can't refresh or update rendering automatically at first.

          I implemented the drawing function according to the document about Scene Graph - Custom Geometry

          Here is my new version of image.qml

          import QtQuick 2.11
          import QtQuick.Window 2.11
          import QtQuick.Controls 1.4
          
          import CustomItem 1.0
          
          Window {
              id: imageWindow
              visible: false
              width: 200
              height: 200
              property alias showImage: showImage
              ToolBar {
                  height: 50
                  Row {
                      ToolButton {
                          width: 70
                          height: 45
                          text: qsTr("Exit")
                          onClicked: imageWindow.close()
                      }
                  }
              }
              Image {
                  id: showImage
                  y: 50
                  onSourceSizeChanged: {
                      imageWindow.height = this.sourceSize.height + 50;
                      imageWindow.width = this.sourceSize.width;
                      mouse.height = this.sourceSize.height;
                      mouse.width = this.sourceSize.width;
                      canvas.height = this.sourceSize.height;
                      canvas.width = this.sourceSize.width;
                  }
              }
              MouseArea {
                  id: mouse
                  y: 50
                  hoverEnabled: true
                  property bool draw: false
                  onPressed: {
                      draw = true;
                      points.addPoint(Qt.point(this.mouseX, this.mouseY));
                      points.addPoint(Qt.point(this.mouseX, this.mouseY));
                  }
                  onPositionChanged: {
                      if (draw === true)
                      {
                          points.setCurrentPoint(Qt.point(this.mouseX, this.mouseY));
                      }
                  }
                  onReleased: draw = false;
              }
              Rectangle {
                  id: canvas
                  y: 50
                  color: "transparent"
                  MyPointPairs {
                      id: points
                  }
              }
          }
          

          I use qmlRegisterType<pointpairs>("CustomItem", 1, 0, "MyPointPairs"); in main.cpp to register pointpairs and here is my pointpairs.h

          #ifndef POINTPAIRS_H
          #define POINTPAIRS_H
          
          #include <QQuickItem>
          
          class pointpairs: public QQuickItem
          {
              Q_OBJECT
          public:
              pointpairs(QQuickItem *parent=nullptr);
              ~pointpairs();
          
              QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *);
          
          public slots:
              void addPoint(const QPointF &p);
              void setCurrentPoint(const QPointF &p);
          
          private:
              QVariantList points;
          };
          
          #endif // CLIENT_H
          

          and pointpairs.cpp

          #include "pointpairs.h"
          
          #include <QSGNode>
          #include <QSGFlatColorMaterial>
          
          pointpairs::pointpairs(QQuickItem *parent)
              : QQuickItem(parent)
          {
              setFlag(ItemHasContents, true);
          }
          
          pointpairs::~pointpairs()
          {
          }
          
          QSGNode *pointpairs::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
          {
              QSGGeometryNode *node = nullptr;
              QSGGeometry *geometry = nullptr;
          
              if (!oldNode)
              {
                  node = new QSGGeometryNode;
                  geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), points.count());
                  geometry->setLineWidth(20);
                  geometry->setDrawingMode(QSGGeometry::DrawLines);
                  node->setGeometry(geometry);
                  node->setFlag(QSGNode::OwnsGeometry);
                  QSGFlatColorMaterial *material = new QSGFlatColorMaterial;
                  material->setColor(QColor(255, 165, 0));
                  node->setMaterial(material);
                  node->setFlag(QSGNode::OwnsMaterial);
              }
              else
              {
                  node = static_cast<QSGGeometryNode *>(oldNode);
                  geometry = node->geometry();
                  geometry->allocate(points.count());
              }
              QSGGeometry::Point2D *vertices = geometry->vertexDataAsPoint2D();
              for (int i=0; i<points.count(); ++i)
              {
                  vertices[i].set(points[i].toPointF().x(), points[i].toPointF().y());
              }
              node->markDirty(QSGNode::DirtyGeometry);
              return node;
          }
          
          void pointpairs::addPoint(const QPointF &p)
          {
              points << p;
              update();
          }
          
          void pointpairs::setCurrentPoint(const QPointF &p)
          {
              points[points.count() - 1] = p;
              update();
          }
          
          DiracsbracketD Offline
          DiracsbracketD Offline
          Diracsbracket
          wrote on last edited by Diracsbracket
          #4

          @wangfys
          I got exactly the same behavior as you. Although I never used the scene graph before, your example (+ the doc and the Custom Geometry example in Qt's examples) gave me a little crash course in the topic.
          http://doc.qt.io/qt-5/qtquick-visualcanvas-scenegraph.html

          Your example really should work as it seems you did everything as required by the doc. At my side, the lines become visible once I hover the mouse one the exit button. Possibly this is a bug?

          PS. Again, not being useful, I maybe I could suggest you to change the definition of your points from QVariantList points; to QVector<QPointF> points;

          Then you can use:

                  const float x = static_cast<float>(points[i].x());
                  const float y = static_cast<float>(points[i].y());
                  vertices[i].set(x, y);
          

          rather than

                vertices[i].set(points[i].toPointF().x(), points[i].toPointF().y());
          

          as it saves you a couple of calls to toPointF().

          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