Qt SVG : Dynamic Modification
-
@jsulm Yes , SVG is made of xml elements. But how to edit the svg file dynamically -> parse the xml element -> update the property-> save the change- > display the updated svg image ??
Is there any code reference ?@Parvathy2020 Did you read the documentation from the link I provided?!
If you need examples here you go: https://doc.qt.io/qt-5/examples-xml.html -
@Parvathy2020 Did you read the documentation from the link I provided?!
If you need examples here you go: https://doc.qt.io/qt-5/examples-xml.html@jsulm Ok thanks
-
@Parvathy2020 Did you read the documentation from the link I provided?!
If you need examples here you go: https://doc.qt.io/qt-5/examples-xml.html@jsulm (as long as I'm replying to old topics today...)
I've got a similar question, best explained through an example. I have a QML TabBar containing several (customized) TabButtons.
When a given tab is selected, the icon is to be filled in; when not selected, it's to be an outline only.The above is easily enough done at the file level by modifying the stroke-opacity field. But, as the OP and you point out, this necessitates file level changes. Impractical, and (I think) impossible when the files are embedded as resources.
I think the answer to my question is "no," but...is there some way to modify the "properties" (for lack of a better term) of the .svg file programmatically? So I can toggle the fill of my image based on tab selection.
Thanks for any ideas...
-
@jsulm (as long as I'm replying to old topics today...)
I've got a similar question, best explained through an example. I have a QML TabBar containing several (customized) TabButtons.
When a given tab is selected, the icon is to be filled in; when not selected, it's to be an outline only.The above is easily enough done at the file level by modifying the stroke-opacity field. But, as the OP and you point out, this necessitates file level changes. Impractical, and (I think) impossible when the files are embedded as resources.
I think the answer to my question is "no," but...is there some way to modify the "properties" (for lack of a better term) of the .svg file programmatically? So I can toggle the fill of my image based on tab selection.
Thanks for any ideas...
-
@fcarney in this case, I'm given .svg files from the UX team. I'd have to translate them into QML Shapes, which I suppose isn't terrible, but being the creatively lazy guy I am, I'm hoping for something more straightforward.
-
@fcarney in this case, I'm given .svg files from the UX team. I'd have to translate them into QML Shapes, which I suppose isn't terrible, but being the creatively lazy guy I am, I'm hoping for something more straightforward.
-
@fcarney in this case, I'm given .svg files from the UX team. I'd have to translate them into QML Shapes, which I suppose isn't terrible, but being the creatively lazy guy I am, I'm hoping for something more straightforward.
@mzimmers said in Qt SVG : Dynamic Modification:
this necessitates file level changes. Impractical, and (I think) impossible when the files are embedded as resources.
You could do string replacements and pass the final document to an
Image
as a Data URL:Window { width: 640 height: 480 visible: true property string svgStr: `<svg xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="50" r="50" fill="${colours.currentText}"/></svg>` ComboBox { id: colours model: ["red", "green", "blue"] } Image { anchors.centerIn: parent source: `data:image/svg+xml;base64,${Qt.btoa(svgStr)}` sourceSize.width: 300 sourceSize.height: 300 } }
-
@mzimmers said in Qt SVG : Dynamic Modification:
this necessitates file level changes. Impractical, and (I think) impossible when the files are embedded as resources.
You could do string replacements and pass the final document to an
Image
as a Data URL:Window { width: 640 height: 480 visible: true property string svgStr: `<svg xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="50" r="50" fill="${colours.currentText}"/></svg>` ComboBox { id: colours model: ["red", "green", "blue"] } Image { anchors.centerIn: parent source: `data:image/svg+xml;base64,${Qt.btoa(svgStr)}` sourceSize.width: 300 sourceSize.height: 300 } }
-
@mzimmers if it is only for icons, did you think about simply converting them into a ligature font (named icons). This way you can use the icons as font in a QML Text element.
Text { font.family: "myLigatureFontName" // e.g. FontAwesome Pro font.pointSize: 32 text: "myLigatureIconName" // e.g. "home" for a house-icon color: "transparent" // font color style: Text.Outline // if you need outline styleColor: "red" // outline color }
-
@mzimmers said in Qt SVG : Dynamic Modification:
(I'll need to build around this, as I'm currently using the icon property of TabButton.)
You're welcome.
Works for button icons too!
TabButton { text: "Click Me" icon.source: `data:image/svg+xml;base64,${Qt.btoa(svgStr)}` }
-
@Parvathy2020 I know this is late, but still.
I have had a very similar issue where we needed to change the color from SVG regions. Our solution was quite unique actually:Use a QGraphicsView with a scene ofcourse and then use the QGraphicsSvgItem (not the normal one). You can then get the svg item by setElementId().
If you use a colorizer on top, you can manipulate the QGraphicsSvgRenderer to overwrite that area with a new color. No need to alter the file directly.//create objects QGraphicsSvgItem* newSvgItem = new QGraphicsSvgItem(); QGraphicsColorizeEffect* newColorizeEffect = new QGraphicsColorizeEffect(nullptr); //--- setup SVG --- //setup renderer newSvgItem->setSharedRenderer(&svgRenderer); //"draw" element on correct position newSvgItem->setElementId(elementId.toString()); newSvgItem->setPos(svgRenderer.boundsOnElement(elementId.toString()).left(), svgRenderer.boundsOnElement(elementId.toString()).top()); //--- colorize effect --- newColorizeEffect->setStrength(colorStrength); newColorizeEffect->setColor(color); newColorizeEffect->setEnabled(true); //link graphics effect newSvgItem->setGraphicsEffect(newColorizeEffect); //setup scene scene.addItem(newSvgItem);
This will select a very specific element from the SVG and adds it to the scene. This is how you can filter as well.
On top of that, if you keep track of your colorizer (using a map or whatever), you can change the color dynamically. -
@fcarney in this case, I'm given .svg files from the UX team. I'd have to translate them into QML Shapes, which I suppose isn't terrible, but being the creatively lazy guy I am, I'm hoping for something more straightforward.
@mzimmers said in Qt SVG : Dynamic Modification:
I'm given .svg files from the UX team. I'd have to translate them into QML Shapes, which I suppose isn't terrible, but being the creatively lazy guy I am, I'm hoping for something more straightforward.
This did not exist at the time of our original discussion, but Qt 6.8 introduced the
svgtoqml
tool: https://doc.qt.io/qt-6/qtqml-tooling-svgtoqml.html Each element gets converted to a Qt Quick Shape which you can colour individually.This would be more efficient than the Data URL method I described earlier, because this doesn't involve re-parsing the whole SVG file every time a colour is updated.
@mr_broccoli said in Qt SVG : Dynamic Modification:
Use a QGraphicsView with a scene ofcourse and then use the QGraphicsSvgItem (not the normal one). You can then get the svg item by setElementId().
If you use a colorizer on top, you can manipulate the QGraphicsSvgRenderer to overwrite that area with a new color. No need to alter the file directly.Thanks for sharing your alternative solution! This is suitable for projects that use Qt Widgets (which are not GPU accelerated, unlike Qt Quick).
-
@mzimmers said in Qt SVG : Dynamic Modification:
I'm given .svg files from the UX team. I'd have to translate them into QML Shapes, which I suppose isn't terrible, but being the creatively lazy guy I am, I'm hoping for something more straightforward.
This did not exist at the time of our original discussion, but Qt 6.8 introduced the
svgtoqml
tool: https://doc.qt.io/qt-6/qtqml-tooling-svgtoqml.html Each element gets converted to a Qt Quick Shape which you can colour individually.This would be more efficient than the Data URL method I described earlier, because this doesn't involve re-parsing the whole SVG file every time a colour is updated.
@mr_broccoli said in Qt SVG : Dynamic Modification:
Use a QGraphicsView with a scene ofcourse and then use the QGraphicsSvgItem (not the normal one). You can then get the svg item by setElementId().
If you use a colorizer on top, you can manipulate the QGraphicsSvgRenderer to overwrite that area with a new color. No need to alter the file directly.Thanks for sharing your alternative solution! This is suitable for projects that use Qt Widgets (which are not GPU accelerated, unlike Qt Quick).
@JKSH said in Qt SVG : Dynamic Modification:
which are GPU accelerated, unlike Qt Quick
Isn't it other way around?
-
@JKSH said in Qt SVG : Dynamic Modification:
which are GPU accelerated, unlike Qt Quick
Isn't it other way around?
@jsulm said in Qt SVG : Dynamic Modification:
@JKSH said in Qt SVG : Dynamic Modification:
which are GPU accelerated, unlike Qt Quick
Isn't it other way around?
Oops! Forgot a "not". Thanks! 😅
-
@mzimmers said in Qt SVG : Dynamic Modification:
I'm given .svg files from the UX team. I'd have to translate them into QML Shapes, which I suppose isn't terrible, but being the creatively lazy guy I am, I'm hoping for something more straightforward.
This did not exist at the time of our original discussion, but Qt 6.8 introduced the
svgtoqml
tool: https://doc.qt.io/qt-6/qtqml-tooling-svgtoqml.html Each element gets converted to a Qt Quick Shape which you can colour individually.This would be more efficient than the Data URL method I described earlier, because this doesn't involve re-parsing the whole SVG file every time a colour is updated.
@mr_broccoli said in Qt SVG : Dynamic Modification:
Use a QGraphicsView with a scene ofcourse and then use the QGraphicsSvgItem (not the normal one). You can then get the svg item by setElementId().
If you use a colorizer on top, you can manipulate the QGraphicsSvgRenderer to overwrite that area with a new color. No need to alter the file directly.Thanks for sharing your alternative solution! This is suitable for projects that use Qt Widgets (which are not GPU accelerated, unlike Qt Quick).
... This is suitable for projects that use Qt Widgets (which are not GPU accelerated, unlike Qt Quick).
What do you mean it is not GPU accelerated? My understanding is that QWidgets use the QPainter device, which is not GPU accelerated. Whiles the Graphics View does. Would you mind pointing out how I could optimise then?
Thanks!
-
... This is suitable for projects that use Qt Widgets (which are not GPU accelerated, unlike Qt Quick).
What do you mean it is not GPU accelerated? My understanding is that QWidgets use the QPainter device, which is not GPU accelerated. Whiles the Graphics View does. Would you mind pointing out how I could optimise then?
Thanks!
@mr_broccoli the graphics view (QGraphicsView) can make use of a QOpenGLWidget as viewport in order to get acceleration but it's not the default.
See here
-
The new svgtoqml tool and VectorImage component might be interesting for this. This will convert the SVG to QML code. The rendering will then be hardware-accelerated (being just Qt Quick under the hood).
In addition, since it generates a tree of Qt Quick items with object names based on the IDs given in the source file, it is possible to traverse it using JavaScript and change properties on specific items as the original post here requested.
Some more details can be found in these blogs if you are interested:
https://www.qt.io/blog/vector-graphics-in-qt-6.8
https://www.qt.io/blog/animated-vector-graphics-in-qt-6.10