简体   繁体   中英

CurrentText property of QML Combo box not changing when read from C++

I am currently using QML/C++ for mobile development and facing a problem that, for sure demonstrates my poor ability to design QML/C++ applications. Hope you can help me here.

This is my main.qml:

import QtQuick 2.12
import QtQuick.Controls 2.5
import QtQuick.Layouts 1.12

ApplicationWindow {
 id: window
 visible: true
 width: 640
 height: 480
 title: qsTr("(Nome da Aplicação)")

header: ToolBar{
    RowLayout{
        anchors.fill: parent
        ToolButton {
            id: toolButton
            text: stackView.depth > 1 ? "\u25C0" : "\u2630"
            onClicked: drawer.open()
        }

        Label {
            text: stackView.currentItem.title
            elide: Label.ElideRight
            horizontalAlignment: Qt.AlignHCenter
            verticalAlignment: Qt.AlignVCenter
            Layout.fillWidth: true
        }
    }
}
Drawer {
    id: drawer
    width: window.width * 0.33
    height: window.height

    Column{
        anchors.fill: parent

        ItemDelegate {
            text: qsTr("Operações")
            width: parent.width
            onClicked: {
                stackView.push("Operacoes.qml")
                drawer.close()
            }
        }
        ItemDelegate {
            text: qsTr("Produtos")
            width: parent.width
            onClicked: {
                stackView.push("Produtos.qml")
                drawer.close()
            }
        }
        ItemDelegate {
            text: qsTr("Configurações")
            width: parent.width
            onClicked: {
                stackView.push("Configuracoes.qml")
                drawer.close()
            }
        }
    }
}

StackView {
    id: stackView
    initialItem: "Operacoes.qml"
    anchors.fill: parent
}
}

The combo box whose value I need to access from C++ is defined in Operacoes.qml which consists of

import QtQuick 2.12
import QtQuick.Controls 2.5
import QtQuick.Layouts 1.3
import QtCharts 2.3

Item {

    objectName: "janelaResumo"

    property alias title: paginaOperacoes.title
    property alias primeiroGraf: primeiroGraf
    property alias segundoGraf: segundoGraf
    property alias terceiroGraf: terceiroGraf
    property alias quartoGraf: quartoGraf
    property alias combo_periodoFaturacao_ID: combo_periodoFaturacao_ID

    Page {
        id: paginaOperacoes
        anchors.fill: parent
        title: "Resumo de Operações"

        ScrollView {
            anchors.fill: parent
            clip: true

            GridLayout {
                id: grid_BaseLayout
                columns: paginaOperacoes.width < 400 ? 1 : 2
                rows: paginaOperacoes.width < 400 ? 4 : 2
                anchors.fill: parent

                ColumnLayout {

                    Label {
                        Layout.alignment: Qt.AlignHCenter
                        text: qsTr("Faturação")
                        font.bold: true
                    }
                    RowLayout {

                        ChartView {
                            id: primeiroGraf
                            width: 350
                            height: 350
                            antialiasing: true

                            PieSeries {
                                name: "PieSeries"
                                PieSlice {
                                    value: 13.5
                                    label: "Slice1"
                                }
                                PieSlice {
                                    value: 10.9
                                    label: "Slice2"
                                }
                                PieSlice {
                                    value: 8.6
                                    label: "Slice3"
                                }
                            }
                        }

                        ComboBox {
                            objectName: "combo_periodoFaturacao"
                            model: ListModel{

                            ListElement {
                                text:"7 dias"
                            }
                            ListElement {
                                text:"Mensal"
                            }
                            ListElement {
                                text:"Anual"
                            }
                            }
                            id: combo_periodoFaturacao_ID
                        }
                    }
                }
                // segundo gráfico
                ColumnLayout {

                    Label {
                        Layout.alignment: Qt.AlignHCenter
                        text: qsTr("Tesouraria")
                        font.bold: true
                    }
                    ChartView {
                        id: segundoGraf
                        width: 350
                        height: 350
                        antialiasing: true

                        PieSeries {
                            name: "PieSeries"
                            PieSlice {
                                value: 13.5
                                label: "Slice1"
                            }
                            PieSlice {
                                value: 10.9
                                label: "Slice2"
                            }
                            PieSlice {
                                value: 8.6
                                label: "Slice3"
                            }
                        }
                    }
                }
        }
    }
}

Then, C++ ClassX class implements a method to load data that should start by reading qml interface values in order to use them as arguments for some future processig.

    void classX::loadData(){
    if(mDbStatus == true){
        QQuickView view;
        const QUrl url(QStringLiteral("qrc:/Operacoes.qml"));
        view.setSource(url);
        QObject *OperacoesObject = view.rootObject();

        QObject *comboFaturacao_t = OperacoesObject->findChild<QObject ("combo_periodoFaturacao");
        qDebug() << comboFaturacao_t->property("currentText");

No matter what value lives in the combobox combo_periodoFaturacao depending on user selection, I always get the same value(first element of the respective combobox model) in comboFaturacao_t->property("currentText");

I am aware that I must avoid referring explicitly my UI from C++! I also understand that, for each loadData() call, I am instantiating a new QQuickView object, but how can I simply collect a few UI values to serve as parameters for the execution of loadData() without implement a cpp class "binded" to my fileX.qml?

No matter what value lives in the combobox comboFaturacao depending on user selection, I always get the same value(first element of the combobox model)

Based on the code you posted, and except if I missed something, you are reading the value of "currentText" immediately after creating your view, without waiting for the user to select anything. So this will return the initial value when your view is created.

but how can I simply collect a few UI values to serve as parameters for the execution of loadData() without implement a cpp class "binded" to my fileX.qml

Exposing C++ to the UI is really the way to go, and a good practice, which forces to avoid high level logic to GUI dependencies. Which means not depending on implementation detail (GUI in this case). That said, if this is what you want, you can read properties from C++, but still need to wait for the user to be "done", which can be done by:

  • Creating the view on the heap instead of the stack and saving it somewhere
  • Connecting a slot like onLoadDataUserSettingsReady to a QML signal, using connect (probably the older SIGNAL/SLOT syntax to allow connecting to an arbitrary signal)
  • Return from loadData , as you will need to wait for the user to interact with the UI without blocking the main thread
  • And whenever you emit your QML signal that says "The user is done", your onLoadDataUserSettingsReady slot will be executed, allowing you to read the QML properties you are interested with (or directly pass them in the signal/slot)

But as you can see, this is a bit complex, and forces you to make loadData asynchronous, which may not be what you want. You could potentially make it synchronous using a thread that's not the main thread, and a QSignalSpy or other to wait for a signal, but again, not a great solution. I would still recommend exposing a C++ instance with setContextProperty , and reading from this object in your loadData method, whenever needed.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM