2015-12-02 26 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