如何调用组件内部定义的函数?

Posted

技术标签:

【中文标题】如何调用组件内部定义的函数?【英文标题】:How to invoke a function defined inside of a component? 【发布时间】:2017-11-27 09:20:50 【问题描述】:

设置

我的系统是 KUbuntu 17.10,Qt 5.9。

我有一个 stackview,它实际上包含更多组件,但为了简洁起见,我将它们删掉了。基本上,当“返回项目”按钮被按下时,submitReturnButton 信号在 C++ 端被捕获。捕获端没有任何状态,它只是尝试发送文本以设置在标签上。


代码

ma​​in.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QObject>
#include <QQuickWindow>

#include "returnserver.h"

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

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

    QQmlApplicationEngine engine;
    engine.load(QUrl(QLatin1String("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;

    //boilerplate ends here

    QObject *topLevel = engine.rootObjects().value(0);
    QQuickWindow *window = qobject_cast<QQuickWindow *>(topLevel);
    QObject* returnStatusLabel = engine.findChild<QObject*>("returnStatusLabel");

    ReturnServer returner(returnStatusLabel);

    QObject::connect(window, SIGNAL(submitReturnForm(QString)), &returner, SLOT(returnPressed(QString)));
    return app.exec();

returnserver.h

#ifndef RETURNSERVER_H
#define RETURNSERVER_H

#include <QObject>
#include <QVariant>
#include <QString>
#include <QQuickWindow>

class ReturnServer : public QObject

    Q_OBJECT

    QObject* target;
public:
    ReturnServer(QObject* target, QObject* parent = nullptr);

public slots:
    void returnPressed(const QString& str);
;

#endif // RETURNSERVER_H

returnserver.cpp

#include "returnserver.h"
#include <QString>
#include <QVariant>

ReturnServer::ReturnServer(QObject* target, QObject *parent) :
    target(target),
    QObject(parent)




void ReturnServer::returnPressed(const QString& str)

    //qDebug() << "the signal got to slot correctly";
    QVariant status = "Returned";

//    emit statusReady(QVariant::fromValue(status));
    QMetaObject::invokeMethod(target, "setReturnStatus", Q_ARG(QVariant, status));

QML

ma​​in.qml 并不真正相关,只是为了表明该应用具有 stackview 并分解为组件

import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.3

ApplicationWindow 
    visible: true
    width: 640
    height: 480
    title: qsTr("Borrowment terminal")

    signal submitReturnForm(string itemID)

    property int lineEditLength: 120
    background: Rectangle
    
        id: mainBackground
        color: "gray"
    

    StackView
    
        id: stack
        initialItem: returnPageComponent
    

    Component
    
        id: returnPageComponent
        ReturnPage
    

ReturnPage.qml:

import QtQuick 2.0
import QtQuick.Layouts 1.3
import QtQuick.Controls 2.2

Item 
    id: returnPageView

    ColumnLayout 
        id: returnPageMenu
        x: 213
        y: 99
        width: 200
        height: 282
        Layout.margins: 20

        //redundant, just to make it compile
        Rectangle 
            width: lineEditLength
            height: 40
            color: "white"
            Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
            TextInput 
                id: itemIDEdit
                width: parent.width
                height: parent.height
                font.pixelSize: 20
                maximumLength: 8
            


        

        //this label I want to set
        Label
        
            id: returnStatusLabel
            objectName: "returnStatusLabel"
            function setReturnStatus(status) 
                console.log("set return status to " + status)
                ReturnPage.returnStatus = status
            
            text: "empty"
            width: 100
            height: 20
            Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
            font.pointSize: 14

        

        Button 
            id: returnItemButton
            width: 75
            height: 30
            text: "Return the Item"
            Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
            onClicked:  submitReturnForm(itemIDEdit.text)
            
    


截图

问题

如果returnStatusLabel 在不同的组件中,我如何调用/设置从 C++ 端发送的某些文本?

我尝试了什么

    main.qml 中创建函数并以根对象为目标从C++ 调用它。

    这确实调用了函数,但没有设置文本。我怀疑这与未使用正确的对象有关,因此与生命周期有关。

    在标签本身中创建函数,在 C++ 中找到对象并以对象作为参数调用函数

    在这种情况下,该函数根本没有被调用,尽管调试器没有抱怨连接设置不正确。

【问题讨论】:

【参考方案1】:

代码太多了......解释你想法的文字很少,因此回答非常复杂,我可能会完全错过重点。

如果 returnStatusLabel 在不同的组件中,我如何调用/设置从 C++ 端发送的某些文本?

你不能。组件只不过是一个声明,或者更好:一个配置工厂来生产某种实例。但是,没有可以调用函数的此类对象的实例。


但我没有看到任何东西在另一个组件中。我只能看到,你犯了从 C++ 端与 QML 端混合的错误。

引用文档:

Warning: 虽然可以使用 C++ 访问和操作深入到对象树中的 QML 对象,但我们建议您不要在应用程序测试和原型设计之外采用这种方法。 QML 和 C++ 集成的一个优势是能够独立于 C++ 逻辑和数据集后端实现 QML 用户界面,如果 C++ 端深入到 QML 组件以直接操作它们,那么这种策略就会中断。例如,如果新组件缺少必需的 objectName,这将使得将 QML 视图组件交换为另一个视图变得困难。 C++实现最好尽量少了解QML用户界面实现和QML对象树的组成。

正确的方法是在 QML 中创建 ResponseServer 的实例,以便您可以在此处轻松地进行连线,或者将 C++ 制作的 ResponseServer 实例公开为上下文QML 的属性或单例实例。 基线是:在 QML 中进行信号的布线。提供值作为您可以轻松绑定的属性

【讨论】:

谢谢,我会进一步研究这个。很抱歉提供了这么多代码,我只是不知道什么是相关的,什么不是,所以我创建了一个最小的工作示例。你能推荐一本关于 Qt Quick 2 及其与 C++ 交互的书或博客吗? 我不太了解 QML 方面的书籍。我一开始使用的唯一 "book" 是:qmlbook.github.io - 但我认为文档也包含大量关于此的信息。这方面也有很多有趣的问题,例如关于创建数据模型等等。 谢谢。结果比完美还好。我在 QML 中注册了 C++ 类型。

以上是关于如何调用组件内部定义的函数?的主要内容,如果未能解决你的问题,请参考以下文章

从 Firebase 存储调用图像 - 无效的钩子调用。 Hooks 只能在函数组件的主体内部调用

在事件处理程序错误中调用钩子(useMutation):“只能在函数组件的主体内部调用钩子”

调用组件内部的函数

在组件内部定义自定义挂钩是不是有任何问题?

javascript 内部函数的定义及调用

组件内部的函数调用