首页 文章

从C(Qt5)向QML项发送信号

提问于
浏览
11

我有一个包含以下内容的QML文件:

Text {
    id: testData
    onTaskClicked:{
        testData.text = task.name
    }
}

捕获是这个任务点击信号 . 它由另一个小部件(C)发出,需要中继到QML .

这类似于this SO question,除了那里发布的解决方案不起作用(为什么写在下面) .

C代码:

ctxt->setContextProperty(QLatin1Literal("holiday"), m_model);
ctxt->setContextProperty(QLatin1Literal("bgcolor"), color);

view->setResizeMode(QQuickView::SizeRootObjectToView);

auto mainPath = QStandardPaths::locate(QStandardPaths::DataLocation,
                                           QLatin1Literal("taskview.qml"));

view->setSource(QUrl::fromLocalFile(mainPath));

ctxt->setContextProperty(QLatin1Literal("viewer"), m_view);

m_viewQListView 子类,它发出 taskClicked(HolidayTask* task) 信号(来自.h文件):

Q_SIGNALS:
    void taskClicked(HolidayTask* task);

colorm_model 在QML中注册并在其他地方使用 . 来自信号的对象已经在QML中注册 . view 是我的 QQuickView .

首先,我尝试了上述问题中提出的解决方案:

auto root = view->rootObject();
auto myElement = root->findChild<QObject*>(QLatin1Literal("testData");

connect(m_view, SIGNAL(taskClicked(HolidayTask* task), myElement,
        SLOT(taskClicked(HolidayTask* task);

但是, myElement 始终为null(我收到有关不存在的插槽的运行时警告) .

如果我尝试将视图(QListView)指针设置为QML视图的上下文属性,它仍然不起作用 .

在所有情况下,我也得到:

QML Connections: Cannot assign to non-existent property "onTaskClicked"

我可能在这里做错了什么?

编辑澄清一些细节: HolidayTask 是自定义QObject子类,信号 taskClicked 在C中定义(在 QListView 子类中)

编辑2:我们越来越近,但没有雪茄:

auto root = quickView->rootObject();
auto myElement = root->findChild<QObject*>(QLatin1Literal("testData"));

connect(m_view, SIGNAL(taskClicked(HolidayTask*)),
        myElement, SIGNAL(taskClicked(HolidayTask* task)));

Text {
    id: testData
    objectName: "testData"
    signal taskClicked(HolidayTask task)
    onTaskClicked: {
        testData.text = task.name
        console.log("CLICk!")
    }
}

产量

QObject::connect: No such signal QQuickText_QML_0::taskClicked(HolidayTask* task) in /home/lb/Coding/cpp/holiday-planner/src/mainwindow.cpp:178
QObject::connect:  (receiver name: 'testData')

更多细节:HolidayTask,我的自定义QObject子类,在代码中注册为

qmlRegisterType<HolidayTask>("HolidayPlanner", 1, 0, "HolidayTask");

带有数据的最小QML:

import QtQuick 2.0
 import QtQml 2.2

import HolidayPlanner 1.0

Rectangle {
    id: container
    objectName: "container"
    color: bgcolor


   Text {
        id: testData
        objectName: "testData"
        signal taskClicked(HolidayTask task)
        onTaskClicked: {
            testData.text = task.name
            console.log("CLICK")
        }
   }

}

EDIT3:最终的工作代码是(查看原因的答案)

connect(m_view, SIGNAL(taskClicked(HolidayPlanner::HolidayTask*)),
        myElement, SIGNAL(taskClicked(HolidayPlanner::HolidayTask*)));

这通过使用具有完整名称空间的对象来实现 only . 否则签名在QML中将不匹配 .

3 回答

  • 1

    但是,myElement始终为null(我收到有关不存在的插槽的运行时警告) .

    您正在尝试基于id查找子项,而它基于objectName属性 . 您需要将objectName属性设置为实际找到它的所需 .

    此外,您似乎没有在QML文本项中声明信号 . 我不确定它是自定义C项还是内置项 . 遗憾的是,您还没有分享足够的代码来理解这一点 . 无论哪种方式,声明您的信号as per documentation .

    因此,请尝试以下代码:

    Text {
        id: testData
        objectName: "testData"
        // ^^^^^^^^^^^^^^^^^^^
        signal taskClicked (HolidayTask task)
        // ^^^^^^^^^^^^^^^^^^^
        onTaskClicked:{
            testData.text = task.name
        }
    }
    

    一旦完成,你几乎准备好了 . 您需要将HolidayTask注册到QML,并且还需要更改main.cpp中的connect语法,如下所示:

    connect(m_view, SIGNAL(taskClicked(HolidayTask* task), myElement, SIGNAL(taskClicked(HolidayTask* task)));
    

    简而言之,您需要以这种方式触发QML信号处理程序,而不是通过 SLOT .

    另请注意,您的连接语法已损坏,因为它缺少最后的右括号 . 这需要修复 .

    我甚至会考虑删除指针赋值并使用值或基于引用的传递 .

  • 6

    您可以通过以下方式将信号从C连接到QML:

    view->rootContext()->setContextProperty("testData",this);
     QObject::connect(this,SIGNAL(taskClicked(HolidayTask* task)),(QObject *)view->rootObject(),SLOT(onTaskClicked(HolidayTask* task)));
    

    当您的信号名为 taskClicked 时,QML中的插槽应为 onTaskClicked .

    同样在QML中,您应该将对象命名为 testData

    objectName: "testData"
    
  • 3
    QML Connections: Cannot assign to non-existent property "onTaskClicked"
    

    该错误告诉您 Text 项目没有信号 taskClicked 或属性 onTaskClicked !您需要在文本项中声明一个插槽 . 为此,您只需声明一个函数:

    Text {
       id: testData
       objectName: "testData" // as Laszlo said
    
       function onTaskClicked( task ) {
           testData.text = task.name;
       }
    }
    

    但是这也行不通,因为你创建的是 SLOT( onTaskClicked(QVariant) ) 而不是 SLOT(taskClicked(HolidayTask*)) . 要与QML交换数据,您需要将信号更改为 SIGNAL(taskClicked(QVariant))

    Q_SIGNALS:
        void taskClicked(QVariant task);
    

    发出它:

    emit taskClicked( QVariant::fromValue( task ) );
    

    请记住,为了能够使用 HolidayTask ,它必须是 QObject ,注册 qmlRegisterType .

    你也可以simply call that qml function .

    如果您无法使用QVariant,您可以在文本对象中声明一个信号:

    Text {
       id: testData
       objectName: "testData" // as Laszlo said
    
       signal taskClicked ( HolidayTask task )
    
       onTaskClicked: {
           testData.text = task.name;
       }
    }
    

    然后从C SIGNAL连接到qml SIGNAL:

    auto root = view->rootObject(); 
    auto myElement = root->findChild<QObject*>(QLatin1Literal("testData");
    connect(m_view, SIGNAL(taskClicked(HolidayTask*), myElement,
        SIGNAL(taskClicked(HolidayTask*));
    

相关问题