在QML中使用信号和插槽方法在main()函数中加载另一页

时间:2019-03-05 04:02:09

标签: c++ qt qml

我的源代码如下:

我有2个qml文件。已从maim.qml文件中调用了第二个qml文件。我想使用信号和插槽方法从第二个qml文件中获取文本。

main.qml文件:

ApplicationWindow {
    id: applicationWindow1
    StackLayout {
        id: swipeView
        anchors.left: sideBar.right
        anchors.right: parent.right
        anchors.bottom: tabBar.top
        anchors.top: parent.top
        currentIndex: tabBar.currentIndex
        firstpage{}
        Secondpage{}
        }
    TabBar {
        id: tabBar
        height: 42
        anchors.bottom: parent.bottom
        anchors.left: sideBar.right
        anchors.right: parent.right
        currentIndex: swipeView.currentIndex
        TabButton {
            text: qsTr("firstpage")
        }
        TabButton {
            text: qsTr("Secondpage")
        }
}

secondpage.qml

Item{
    signal submitTextField(string text)

    // this function is our QML slot
    function setTextField(text){
        console.log("setTextField: " + text)
        textField1.text = text
    }

    visible: true
    width: 360
    height: 360

    TextField {
        id: textField1
        x: 31
        y: 169
        placeholderText: qsTr("Enter some text...")
    }

    Button {
        x: 193
        y: 167
        text: qsTr("Uppercase me!")

        onClicked:
            // emit the submitTextField signal
            submitTextField(textField1.text)
    }

}

代码C ++:HandleTextField.h文件

class HandleTextField : public QObject
{

        Q_OBJECT
    public:
        explicit HandleTextField(QObject *parent = 0) {}

    signals:
        void setTextField(QVariant text);

    public slots:
        void handleSubmitTextField(const QString& in)
       {
        qDebug() << "c++: HandleTextField::handleSubmitTextField:" << in;
        emit setTextField(in.toUpper());  
       }

}

main.cpp文件

int main(int argc, char *argv[])
{

    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;
    QQuickView view;
    view.setSource(QUrl(QStringLiteral("qrc:/secondpage.qml")));
    QObject *item = view.rootObject();

    HandleTextField handleTextField ;

    QObject::connect(item,SIGNAL(submitTextField(QString)),&handleTextField ,SLOT(handleSubmitTextField(QString)));
    QObject::connect(&handleTextField ,SIGNAL(setTextField(QVariant)),item,SLOT(setTextField(QVariant)));

    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;
    return app.exec();

}

->>当我按下按钮时,没有任何动作。请告诉我我在做什么错。

谢谢

2 个答案:

答案 0 :(得分:0)

该代码最明显的问题是,您实际上从未使用过创建并secondpage到的connect()实例。也没有在其中创建QQuickView的{​​{1}}。 QQmlApplicationEngine是您加载并显示main.qml的地方,并且在其中创建了secondpage的全新实例。

假设您有使用中间HandleTextField类的正当理由(而不是仅在不涉及C ++的QML中直接连接QML信号/插槽),那么我建议您采用另一种策略。看起来您至少已经读过Interacting with QML Objects from C+的某些内容,但要特别注意此特定部分中显示的警告

  

警告:尽管可以从C ++访问QML对象并对其进行操作,但除测试和原型设计目的外,不建议使用此方法。 ...

要修复您现有的代码(如果最终选择此路由):

main.qml

ApplicationWindow {
    id: applicationWindow1
    StackLayout {
        id: swipeView
        ...
        Secondpage {
            objectName: "mySecondPage"  // add an object name
        }
    }
    ...
}

main.cpp

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;
    // First load the main QML file, which also loads the Secondpage item you want to access.
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;

    HandleTextField handleTextField;

    // Here we find the "Secondpage" item loaded into main.qml by its objectName property
    QObject *item = engine.rootObjects().first()->findChild<QObject *>("mySecondPage");
    if (item) {
        QObject::connect(item, SIGNAL(submitTextField(QString)), &handleTextField, SLOT(handleSubmitTextField(QString)));
        QObject::connect(&handleTextField, SIGNAL(setTextField(QVariant)), item, SLOT(setTextField(QVariant)));
    }

    return app.exec();
}

注意:代码未经测试。检查stderr(控制台)上来自Qt的任何警告,以确保这些connect()操作实际上成功完成。这种方法的另一个问题是,“旧样式” Qt连接只能在运行时进行验证(与“新样式”在编译时进行验证),并且只有在积极查看{{ 1}}输出。但这是连接到QML信号/插槽的唯一方法。

答案 1 :(得分:0)

您的第一个错误是您认为使用QQuickView创建的窗口与在main.qml中创建的窗口相同,因为不是,它们是2个不同的对象。

QML和C ++有2 approaches可以交互:

  • Pulling References from QML:这是您要实现的方法,但是它有很多不便之处,因为使用例如您没有使用的对象名来搜索对象,除了在复杂结构中之外,还很复杂还是无法获得,除了很多QML对象是由您在另一时间获得的对象创建和销毁的,我可以指向非保留内存,而且C ++代码对QML有依赖性,所以这种方法是不是最好的,也不推荐。

  • Pushing References to QML:此方法没有问题,因为使用setContextProperty导出对象时,该对象在所有QML中都是可见的,因为它是全局的,因此,如果创建或消除了QML对象,则不会会产生类似前一种方法的问题,我们不需要对象名,就可以像在QML中创建对象一样建立连接。

如上所述,我将使用第二种方法:

main.cpp

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);
    HandleTextField handleTextField;
    QQmlApplicationEngine engine;
    engine.rootContext()->setContextProperty("handleTextField", &handleTextField);
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;
    return app.exec();
}

Secondpage.qml

Item{
    Connections{
        target: handleTextField
        onSetTextField: textField1.text = text // <---
    }
    visible: true
    width: 360
    height: 360
    TextField {
        id: textField1
        x: 31
        y: 169
        placeholderText: qsTr("Enter some text...")
    }
    Button {
        x: 193
        y: 167
        text: qsTr("Uppercase me!")
        onClicked: handleTextField.handleSubmitTextField(textField1.text) // <---
    }
}

main.qml 不应修改。