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

时间:2014-04-09 05:48:57

标签: c++ qt qml qt5 qtquick2

我有一个包含以下内容的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_view是一个QListView子类,用于发出taskClicked(HolidayTask* task)信号(来自.h文件):

Q_SIGNALS:
    void taskClicked(HolidayTask* task);

colorm_model已在QML中注册,并在其他地方使用。来自信号的对象已经在QML中注册。 viewQQuickView

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

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子类中)

EDIT2:我们已经接近了,但没有雪茄:

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*)));

通过使用具有完整名称空间的对象,这只能 。否则签名在QML中将不匹配。

3 个答案:

答案 0 :(得分:6)

  

但是,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(m_view, SIGNAL(taskClicked(HolidayTask* task), myElement, SIGNAL(taskClicked(HolidayTask* task)));

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

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

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

答案 1 :(得分:4)

您可以通过以下方式将信号从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"

答案 2 :(得分:1)

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对象中声明一个信号:

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*));