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 receivingsourceSizeChanged
signal.This image for test is 256*256:
And I get a result like this:
There is an empty hole that looks like 200*200. After I drag the edge of the window it becomes normal immediately.
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. UsingonSourceChanged
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.
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:
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 aclicked
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");
inmain.cpp
to registerpointpairs
and here is mypointpairs.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.htmlYour 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
fromQVariantList points;
toQVector<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()
.