Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Rendering error after changing the size of Window



  • 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?



  • @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;
    


  • @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();
    }
    


  • @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().


Log in to reply