Home > Enterprise >  Is it possible to control which items are loaded into a QML file depending on a parameter?
Is it possible to control which items are loaded into a QML file depending on a parameter?

Time:10-09

Question is on the title. Let me give an example to make it clear, let's say I have 2 products and each have different features; therefore, I need to put different items and elements on the Main qml file. So far I have tried controlling elements using Q_PROPERTY and visible feature together to check if the parameter has desired value. However, it causes to a total mess, the anchor connections etc. becomes totally uncontrollable because the design also changes, subtly(not critical changes).

So, in short I am looking for a structure that takes a parameter and loads components accordingly.

I also leave an example of what I have done:

In a class,

Q_PROPERTY(int productType READ getproductType  WRITE setproductType  NOTIFY productType Changed);

And in a qml, I let user to choose which product they have:

    Button {
        id: id_typeSelector
        text: "Type 1"
        anchors.left: parent.left
        anchors.top: parent.top


        onClicked: {
            visible: false
            object.setproductType(0)
            splash.timeout()
        }
    }

Lastly, on main.qml i determine which component to be showed:

visible: productType === 0

CodePudding user response:

I think what you need is the dynamic loading of a component. One way to do this is through the use of Loaders. The following is an example of how to constraint pipe size input based on the pipe material chosen.

  • wood pipes: 3", 5" or 7" diameter
  • iron pipe: any diameter
  • steel pipes: 3" - 8" diameter
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
Page {
    anchors.fill: parent
    ListModel {
        id: pipes
        ListElement { pipeTypeName: "Wood"; productType: 0 }
        ListElement { pipeTypeName: "Iron"; productType: 1 }
        ListElement { pipeTypeName: "Steel"; productType: 2 }
    }
    Frame {
        ColumnLayout {
            ComboBox {
                id: comboBox
                model: pipes
                textRole: "pipeTypeName"
                property int currentProductType: pipes.get(currentIndex).productType ?? -1
            }
            Loader {
                sourceComponent: comboBox.currentProductType === 0 && woodInputComponent
                       || comboBox.currentProductType === 1 && ironInputComponent
                       || comboBox.currentProductType === 2 && steelInputComponent
                       || null
            }
        }
    }
    Component {
        id: woodInputComponent
        RowLayout {
            Layout.fillWidth: true
            Text { text: qsTr("Wood Pipe Width: ") }
            ComboBox { model: [3, 5, 7] }
        }
    }
    Component {
        id: ironInputComponent
        RowLayout {
            Layout.fillWidth: true
            TextField { placeholderText: qsTr("Iron Pipe Width") }
        }
    }
    Component {
        id: steelInputComponent
        RowLayout {
            Layout.fillWidth: true
            Text { text: qsTr("Steel Pipe Width") }
            RangeSlider { from: 3; to: 8 }
        }
    }
}

You can Try it Online!

In the above example, I used the following way of choosing dynamically loading a component, i.e.

Loader {
    sourceComponent: comboBox.currentProductType === 0 && woodInputComponent
                  || comboBox.currentProductType === 1 && ironInputComponent
                  || comboBox.currentProductType === 2 && steelInputComponent
                  || null
}

If your components where declared in their own QML, e.g. WoodInput.qml, IronInput.qml and SteelInput.qml, we can consider refactoring the code to something shorter, e.g.

Loader {
    source: pipeTypeName   "Input.qml"
}
  • Related