QSvgRenderer and QByteArray problem
-
This is a question about my using QSvgRenderer and it not behaving as I would expect. Now initially that sounds scary, because I'm probably the only one using it here, but don't let it put you off this question: it might be a question about
QByteArray
and strings instead... :)I have some SVG I am loading into a QGraphicsSvgItem. What it is/does really shouldn't matter, but someone will want to know, so here it is:
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <svg version="1.1"> <g id="src/plugins/projectexplorer/images/buildstepdisable"> <rect style="fill:#ffffff;fill-opacity:1" width="16" height="16" x="48" y="552" /> <circle style="fill:none;fill-opacity:0;stroke:#000000;stroke-width:1.42;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" cx="56" cy="560" r="5.2929001" /> <path d="m 52,564 c 8,-8 8,-8 8,-8" style="fill:none;stroke:#000000;stroke-width:1.42;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> </g> </svg>
Now, if I have just this in a file and I create via
QSvgRenderer *svgRenderer = new QSvgRenderer(QString("/home/jon/QtTests/QtSvg/qtcreatoricons2.svg")); QGraphicsSvgItem *svgItem = new QGraphicsSvgItem(this); svgItem->setSharedRenderer(svgRenderer);
all is well, the icon gets rendered fine.
But I don't want such a small piece of literal in a file. I want to do it from a literal string in code. I'm going to need to use the constructor QSvgRenderer::QSvgRenderer(const QByteArray &contents, QObject *parent = nullptr), right?
Constructs a new renderer with the given parent and loads the SVG data from the byte array specified by contents.
So I'm going to need a
QByteArray
. I copy & paste the above file content into code:static QByteArray svg = R"( <?xml version="1.0" encoding="UTF-8" standalone="no"?> ... )"; QSvgRenderer *svgRenderer = new QSvgRenderer(svg);
No icon now appears.
QSvgRenderer
&QGraphicsSvgItem
are pretty (totally) quiet when they don't get what they want, so I don't get any message to tell me what might have happened. But no icon appearing happens whenever the SVG presented is not acceptable, that must be the case. [UPDATE: Yes: I found bool QSvgRenderer::isValid() const, sure enough that returns true when initialised from my file but false when from my byte array.]Why? Is there anything wrong with my
R"( ... )"
around all that file content? Or assigning it to aQByteArray
? How can I "debug" what the issue is (no, I don't have Qt sources)? -
@JonB
ok, your problem is simply that your XML starts with an empty line, which makes it invalid.
The check of mine above prints:XML Error: "invalid name for processing instruction 2 22"
Change
R"( <?xml version="1.0" encoding="UTF-8" standalone="no"?> .....
to
R"(<?xml version="1.0" encoding="UTF-8" standalone="no"?> ....
and it should work.
-
@JonB Both constructors do
/*! Loads the specified SVG format \a contents, returning true if the content was successfully parsed; otherwise returns false. */ bool QSvgRenderer::load(const QByteArray &contents) { Q_D(QSvgRenderer); return loadDocument(this, d, contents); }
but I don't have the sources to dig deeper. What could you possibly test is if your QByteArray is same as the content of the file, maybe load the content of the file into QByteArray and try too?
-
@artwaw
Well, I know there are some differences. In file the lines are against the left-margin, in the literal string the lines start with whitespace per the pasted indentation in code inside theR"( ... ")
. But whitespace shouldn't be relevant here.....Let me go at least do as you say and load the file into memory
QByteArray
and see how it goes.... -
@artwaw
Well, what a surprise (not!), of course it works if I open the file and read in its bytes.
The question is: why is my literalR(" ... )"
, where the...
is replaced by pasting the whole of the file content into the code, not producing a similarly-acceptableQByteArray
content...?To be sure, a copy paste of what I have in code reads:
static QByteArray svg = R"( <?xml version="1.0" encoding="UTF-8" standalone="no"?> <svg version="1.1"> <g id="src/plugins/projectexplorer/images/buildstepdisable"> <rect style="fill:#ffffff;fill-opacity:1" width="16" height="16" x="48" y="552" /> <circle style="fill:none;fill-opacity:0;stroke:#000000;stroke-width:1.42;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" cx="56" cy="560" r="5.2929001" /> <path d="m 52,564 c 8,-8 8,-8 8,-8" style="fill:none;stroke:#000000;stroke-width:1.42;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> </g> </svg> )";
Can anyone spot anything wrong?
-
@JonB
A quick way if the XML is still valid after you created the bytearray:QDomDocument doc; int errorLine, errorColumn; QString errorMsg; if( !doc.setContent(data, &errorMsg, &errorLine, &errorColumn ) ) qDebug() << "XML Error:" << errorMsg << errorLine << errorColumn;
-
@JonB
ok, your problem is simply that your XML starts with an empty line, which makes it invalid.
The check of mine above prints:XML Error: "invalid name for processing instruction 2 22"
Change
R"( <?xml version="1.0" encoding="UTF-8" standalone="no"?> .....
to
R"(<?xml version="1.0" encoding="UTF-8" standalone="no"?> ....
and it should work.
-
@raven-worx said in QSvgRenderer and QByteArray problem:
ok, your problem is simply that your XML starts with an empty line, which makes it invalid.
I literally had just wondered about exactly this myself (honest!), and was about to test removing it when you replied!
I like your idea of the XML read, I agree that would have told me the problem here. But --- just to verify --- there is no way I can get that error message out of
new QSvgRenderer(QByteArray svg)
call, is there? -
@JonB said in QSvgRenderer and QByteArray problem:
there is no way I can get that error message out of new QSvgRenderer(QByteArray svg) call, is there?
no. You can jsut check the return value of
load()
orisValid()
-
@raven-worx
Yeah, I want alastLoadError()
method :)It's working now, I'll mark your earlier as the solution, thank you :)
-
@raven-worx
If you're still here, one quick not-quite-related question, else I might have to open a new topic....Do you happen to know: I am using this
QGraphicsSvgItem
to put a small "icon overlay" on aQGraphicsPixmapItem
. Problem: I allow "zoom" (via mousewheel) on the graphics items/view/scene. Works fine, theQGraphicsPixmapItem
with their pixmaps grow/shrink. But thisQGraphicsSvgItem
icon overlay --- which is a child of theQGraphicsPixmapItem
--- does not change size in response. SVG does not scale?QGraphicsSvgItem
does not scale? The particular SVG I am using is set not to scale? Any idea what I should do?EDIT Hang on, sorry, I may be mistaken. At present the overlay icon is so small it's hard to tell, maybe it is scaling and I can't see. I need to go make it bigger....
-
@JonB You may need to override func shape to change the size of your icon. This is how I draw my circle inside my class RadioNode : public QGraphicsSvgItem. Catch mouse wheel event and set new diameter, then update?
QPainterPath RadioNode::shape() const { QPainterPath path; path.addEllipse( -m_diameter * 0.5, -m_diameter * 0.5, m_diameter, m_diameter ); return path; }