Basically, I was trying to recreate IconLabel with some of my own classes in QML. However, it worked, in a limited sense:
import QtQuick 2.15
import QtQuick.Controls.Material 2.15
import QtQuick.Layouts 1.15
Item {
id: root
property int spacing: 8
property string direction: "left"
property string icon: ""
property bool is_img: false
property int icon_size: 24
property int font_size: 14
property string text: ""
property string font: "Roboto"
property color color: "black"
property color icon_color: "black"
property color text_color: "black"
Component.onCompleted: {
var cmd = `
import QtQuick 2.15
import QtQuick.Controls.Material 2.15
import QtQuick.Layouts 1.15
`;
var isHorizontal = direction === "left" || direction === "right";
var alignmentCmd = `Layout.alignment: ${isHorizontal ? "Qt.AlignVCenter" : "Qt.AlignHCenter"}`;
var iconCmd = "";
if (icon_color === "black")
icon_color = color;
if (text_color === "black")
text_color = color;
if (root.icon !== "") {
if (is_img) {
iconCmd = `MImage {
source: "${icon}"
Layout.alignment: ${isHorizontal ? "Qt.AlignVCenter" : "Qt.AlignHCenter"}
Layout.fillWidth: true
Layout.fillHeight: true
fillMode: Image.PreserveAspectCrop
width: ${icon_size}
height: ${icon_size}
}`;
} else {
iconCmd = `MIcon {
icon: root.icon
color: root.icon_color
${alignmentCmd}
width: ${icon_size}
height: ${icon_size}
}`;
}
}
var textCmd = `
Text {
text: root.text
font.pixelSize: root.font_size
font.family: root.font
color: root.text_color
${alignmentCmd}
}
`;
var componentCmd = direction === "left" || direction === "top" ? iconCmd textCmd : textCmd iconCmd;
cmd = `
${isHorizontal ? "RowLayout" : "ColumnLayout"} {
spacing: ${isHorizontal ? "root.spacing" : "0"}
${componentCmd}
}`;
Qt.createQmlObject(cmd, root, "dynamicComponent");
}
}
It does do everything that I want if I used it alone, like
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import QtQuick.Dialogs
import QtQuick.Controls.Material 2.15
import "components"
ApplicationWindow {
id: root
visible: true
width: 640
height: 480
title: qsTr("Hello World")
MIconLabel {
icon_color: Material.color(Material.Red, Material.Shade500)
direction: "right"
icon: "home"
text: "Home"
}
MIconLabel {
icon_color: "black"
icon: "menu"
text: "Menu"
y: 100
}
}
But for some reason, it rejects to cooperate with RowLayout or anything of this nature.
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import QtQuick.Dialogs
import QtQuick.Controls.Material 2.15
import "components"
ApplicationWindow {
id: root
visible: true
width: 640
height: 480
title: qsTr("Hello World")
ColumnLayout {
MIconLabel {
icon_color: Material.color(Material.Red, Material.Shade500)
direction: "right"
icon: "home"
text: "Home"
}
MIconLabel {
icon_color: "black"
icon: "menu"
text: "Menu"
}
}
}
Hence, I ask if there is some way that I can make the parent detect the newly created objects (like refresh or remeasure methods?). I tried to resize the window in hope of repainting the event, but nothing good happens. I also used console.log
at the end of the initialization method to print out the dimension of the newly created object, and the dimension of the root object, and the following expression evaluates to True
: root.width == object.width == root.childrenRect.width
and root.height == object.height == root.childrenRect.height
.
Just to explain some details here: MIcon
is a wrapper of Text
class with the font.family
pre-declared as Material Icons
. And MImage
is basically an wrapper around Image with rounded corners and a placeholder, if no image is provided.
CodePudding user response:
It took sometime to read your code. My reading of your code, I get the feeling it is (1) brutal use of createQmlObject() and I would recommend finding another way to do the same thing. For example, are you aware that most components have an icon.source
property with icon.color
? For instance
ItemDelegate {
icon.source: "..."
icon.color: "..."
}
I tried to recreate your UI with:
ItemDelegate
to render both text and iconicon.source
andicon.color
to colorize an SVGLayoutMirroring
to implement both left-to-right and right-to-left patterns- Added
Frame
component to visually check that the dimensions of the attempt
Here's the complete working example:
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
Page {
ColumnLayout {
width: parent.width
Frame {
ItemDelegate {
text: "Home"
icon.source: "home-32.svg"
icon.color: "red"
LayoutMirroring.enabled: true
}
}
Frame {
ItemDelegate {
text: "Menu"
icon.source: "hamburger-32.svg"
icon.color: "black"
}
}
}
}
//home-32.svg
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="M11 8.5V5H6v8.5L2.5 17H5v12h8v-8h6v8h8V17h2.5L16 3.5zM26 16v12h-6v-8h-8v8H6V16H4.914L7 13.914V6h3v4.914l6-6L27.086 16z"/><path fill="none" d="M0 0h32v32H0z"/></svg>
//hamburger-32.svg
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="M28 7H4V6h24zm0 9H4v1h24zm0 10H4v1h24z"/><path fill="none" d="M0 0h32v32H0z"/></svg>
As Stephen Quan suggested, such a brutal amount of createQmlObject is bad. Hence, an alternative solution is proposed, despite it lacks of the ability to create IconLabel in all kinds of directions.
import QtQuick 2.15
import QtQuick.Controls.Material 2.15
import QtQuick.Layouts 1.15
Rectangle {
id: root
property color color: "black"
property alias spacing: rowLayout.spacing
property alias icon: icon.icon
property alias text: text.text
property alias text_size: text.font.pixelSize
property alias icon_size: icon.size
property alias font: text.font.family
property var icon_color: null
property var text_color: null
implicitHeight: rowLayout.implicitHeight
implicitWidth: rowLayout.implicitWidth
RowLayout {
id: rowLayout
anchors.fill: parent
MIcon {
id: icon
icon: root.icon
size: root.icon_size
Layout.alignment: Qt.AlignVCenter
}
Text {
id: text
Layout.alignment: Qt.AlignVCenter
}
}
Connections {
function onColorChanged() {
root.icon_color = root.color
root.text_color = root.color
}
function onIcon_colorChanged() {
icon.color = root.icon_color
}
function onText_colorChanged() {
text.color = root.text_color
}
}
Component.onCompleted: {
if (root.icon_color == null) {
root.icon_color = root.color
}
if (root.text_color == null) {
root.text_color = root.color
}
}
}