2015-12-02 64 views
2

我正在开发一个基本的qml-cpp应用程序,以了解如何与另一个进行交互。我有一个MessageSetter C++类和一个main.qml。由于我希望了解双向通信,因此我使用setContextProperty将MessageSetter属性暴露给qml,并且还使用qml注册了MessageSetter类(可实例化注册)。暴露的属性工作正常。现在,当点击qml按钮时,信号(qmlBtnClicked)被成功捕获到MessageSetter槽(onQmlButtonClicked)中。此槽还会发出另一个MessageSetter信号(colorChanged)。这个新的(C++)信号应该被注册到qml注册的MessageSetter的信号处理程序(onColorChanged)中,但它在任何情况下都不会到达。下面是main.cpp中的代码:如何在类型注册后在QML信号处理程序中捕捉C++信号?

int main(int argc, char *argv[]) 
{ 
    QGuiApplication app(argc, argv); 
    QQmlApplicationEngine engine; 
    qmlRegisterType<MessageSetter>("com.SkillLotto.MessageSetter", 1, 0, "SetMessage"); 

    MessageSetter data; 
    engine.rootContext()->setContextProperty("msgSetter", &data); 
    QQmlComponent component(&engine, QUrl::fromLocalFile("main.qml")); 

    QObject *object = component.create()->findChild<QObject*>("setTextBtn"); 
    QObject::connect(object, SIGNAL(qmlBtnClicked()), &data, SLOT(onQmlButtonClicked())); 

    return app.exec(); 
} 

这是MessageSetter插槽发出另一个信号:

void MessageSetter::onQmlButtonClicked() 
{ 
    emit colorChanged("red"); 
} 

这是QML代码,该信号处理程序不会被调用:

SetMessage{ 
    onColorChanged: { 
     rect.color = color //rect is some rectangle in this file. 
    } 
} 

由于我说过,qml信号被成功捕获在C++插槽中,但是我无法在qml信号处理程序中捕获到这个C++信号。请任何帮助。

正如我所看到的,这个问题集中在qmlRegisterType()上,不应该是this question的重复?我也想知道是否qmlRegisterType()和setContextProperty()不能同时使用?

+0

这是我通过这种方式完成的链接。请让我知道如果我没有把它弄清楚(暴露信号部分)。 http://doc.qt.io/qt-5/qtqml-cppintegration-exposecppattributes.html – Jatin

+0

你说得对。这个问题没有解决[这里](http://stackoverflow.com/questions/8834147/c-signal-to-qml-slot-in-qt)。我刚刚用一个例子回答。 – Tarod

回答

1

我觉得你的代码应该很好地工作。

我没有整个代码,所以我不知道你是否实施了正确的方法。

为了使用qmlRegisterType获得信号,您需要一些要求。检查您是否实施了Q_PROPERTY宏调用。任何可写属性都应该有一个关联的NOTIFY信号,每当属性值发生变化时就会发出。

如果是这样,当你更改组件color特性,信号onColorChanged应该被触发。

这里有一个示例,其中发出两个信号:更新大小属性时的第一个和如果使用MouseArea调用C++ mouseClick方法的第二个信号。

顺便说一句,你不需要setContextProperty来将你的C++类与QML整合。qmlRegisterType应该足够了。反之亦然,取决于您的需求。你可以同时使用,但是你会有两个不同的对象来处理。这真的取决于你想达到什么。

的main.cpp

#include <QGuiApplication> 
#include <QQmlApplicationEngine> 
#include <QtQml> 
#include "customitem.h" 

int main(int argc, char *argv[]) 
{ 
    QGuiApplication app(argc, argv); 
    qmlRegisterType<CustomItem>("CustomItem", 1,0, "CustomItem"); 

    QQmlApplicationEngine engine; 
    engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); 

    return app.exec(); 
} 

customitem.h

#ifndef CUSTOMITEM_H 
#define CUSTOMITEM_H 

#include <QObject> 

class CustomItem: public QObject 
{ 
    Q_OBJECT 

    /* 
    * Any property that is writable should have an associated NOTIFY signal. 
    * Ref: http://doc.qt.io/qt-5/qtqml-cppintegration-exposecppattributes.html#exposing-properties 
    */ 

    Q_PROPERTY(int size READ size WRITE setSize NOTIFY sizeChanged) 

public: 
    CustomItem(QObject *parent = 0); 

    int size() const; 
    void setSize(int); 

    Q_INVOKABLE void mouseClick(); 

private: 
    int m_size; 

signals: 
    void sizeChanged(int size); 
    void clicked(); 

public slots: 
}; 

#endif // CUSTOMITEM_H 

customitem.cpp

#include "customitem.h" 
#include <QDebug> 

CustomItem::CustomItem(QObject *parent) 
: QObject(parent), m_size(0) 
{ 
} 

int CustomItem::size() const 
{ 
    return m_size; 
} 

void CustomItem::setSize(int size) 
{ 
    m_size = size; 
    emit sizeChanged(m_size); 
} 

void CustomItem::mouseClick() 
{ 
    qDebug() << "CustomItem::mouseClick()"; 

    emit clicked(); 
} 

main.qml

import QtQuick 2.5 
import QtQuick.Window 2.2 
import CustomItem 1.0 

Window { 
    visible: true 

    TextInput { 
     id: mySize 
     x: 0 
     y: 0 
     text: "100" 
    } 

    CustomItem { 
     id: customItem 
     size: mySize.text 

     onSizeChanged: console.log("size changed:", size) 
     onClicked: console.log("onClicked!") 
    } 

    Rectangle { 
     id: rect 
     x: 50 
     y: 50 
     width: customItem.size 
     height: customItem.size 
     color: "red" 

     MouseArea { 
      anchors.fill: parent 
      onClicked: { customItem.mouseClick() } 
     } 
    } 
} 
+0

好吧,正如我所希望的那样,您的回答集中在qmlRegisterType上,并且非常有用。但我现在面临的一个问题是;当我在Qt 5.4.2中执行你的代码时,它工作正常。而且它在Qt 5.5.0中不起作用。问题与我的代码相同。 C++槽被调用,但不是QML槽。为什么它的行为如此?我在Qt 5.5.0上工作。 – Jatin

+0

@贾丁很高兴知道这很有用。那么,我也在Qt 5.5.0上工作。该代码在Windows 7中使用该Qt版本编译。我[上传](https://github.com/ftena/qml-c/tree/master/adding-types)代码到GitHub。你可以下载并重试。你能在另一台计算机上编译和运行该应用程序吗? – Tarod

+0

感谢您的GitHub上传。我认为你是对的,我的代码应该工作。但是这个问题可能与Fedora 22,我的操作系统有关。我也在同一个操作系统上尝试过你的代码,但是不同的电脑上在那里,它也有同样的问题'QML插槽没有被调用'。我还遇到了诸如'qDebug'和'console.log'等问题,无法在此操作系统上打印。无论如何,欢迎您的支持。 – Jatin

2

由于您使用的是MessageSetter的两种不同情况,一种是在main.cppdata等是新实例。只能使用一个连接两个信号/插槽。

您期待的信号为onColorChanged,但信号来自data(在main.cpp中)。

为什么你需要可实例化如果你想创建一个上下文属性?


添加这在main.qml文件

Connections { 
    target: msgSetter 
    onColorChanged: { 
    console.log("received color changed signal"); 
    } 
} 
+0

我感谢您的回复。那么,这不是任何项目,只是一个学习应用程序。我想知道如何在QML信号处理程序中捕捉C++信号。这就是为什么要这样做:setContext和qmlRegisterType。 – Jatin

+0

我明白了,你是从一个物体发出信号,并期望从另一个物体发出信号。那就是问题所在。 – ramtheconqueror

+0

你是对的!我感谢您的帮助。如果我不必使用Connections {}并仅使用qmlRegisterType,那么我们有办法吗? – Jatin