Exposing Attributes of C++ Types to QML
Qt 2017. 6. 10. 22:12[원문] https://doc.qt.io/qt-5/qtqml-cppintegration-exposecppattributes.html
Exposing Attributes of C++ Types to QML
QML은 C++ 코드에 정의 된 기능으로 쉽게 확장 할 수 있습니다. QML 엔진과 Qt 메타 객체 시스템 의 긴밀한 통합으로 인해 QObject 기반 클래스 에 의해 적절히 노출되는 모든 기능은 QML 코드에서 액세스 할 수 있습니다. 이를 통해 QML에서 C++ 데이터 및 함수에 직접 액세스 할 수 있습니다. 수정 작업은 거의 또는 전혀 필요하지 않습니다.
QML 엔진에는 메타 오브젝트 시스템을 통해 QObject 인스턴스 를 인트로 스페어 할 수있는 기능이 있습니다. 즉, 모든 QML 코드는 QObject에서 파생 된 클래스 의 인스턴스의 다음 멤버에 액세스 할 수 있습니다 .
> Properties
> Methods (providing they are public slots or flagged with Q_INVOKABLE)
> Signals
(또한 열거 형은 Q_ENUMS로 선언 된 경우 사용할 수 있습니다. 자세한 내용은 QML과 C++ 간의 데이터 형식 변환 을 참조하십시오.)
일반적으로 QObject에서 파생 된 클래스가 QML 유형 시스템 에 등록되었는지 여부에 관계없이 QML 에서 액세스 할 수 있습니다 . 그러나 엔진이 추가 형식 정보에 액세스해야하는 방식으로 클래스를 사용하는 경우 (예 : 클래스 자체를 메서드 매개 변수 또는 속성으로 사용하거나 해당 열거 형식 중 하나를 사용하려는 경우) 이 방법으로 사용되면 클래스를 등록해야 할 수도 있습니다.
또한이 문서에서 다루는 많은 중요한 개념은 Q ++ Extension with C++ 자습서에 나와 있습니다.
Data Type Handling and Ownership
속성 값, 메서드 매개 변수 또는 반환 값 또는 신호 매개 변수 값으로 C++에서 QML로 전송되는 모든 데이터는 QML 엔진에서 지원하는 형식이어야합니다.
기본적으로 엔진은 여러 Qt C++ 유형을 지원하며 QML에서 사용할 때 자동으로 적절하게 변환 할 수 있습니다. 또한 QML 유형 시스템 에 등록 된 C++ 클래스는 적절하게 등록 된 경우 해당 열거 형과 마찬가지로 데이터 유형으로 사용할 수 있습니다. 자세한 내용은 QML과 C++ 간의 데이터 형식 변환을 참조하십시오 .
또한 데이터 소유권 규칙은 데이터가 C++에서 QML로 전송 될 때 고려됩니다. 자세한 내용은 데이터 소유권 을 참조하십시오.
Exposing Properties
속성은 어떤 지정할 수 있습니다 QObject를 사용하여 유도 된 클래스 Q_PROPERTY () 매크로를. 속성은 연관된 읽기 함수와 선택적 쓰기 함수가있는 클래스 데이터 멤버입니다.
QObject에서 파생 된 클래스 의 모든 속성은 QML에서 액세스 할 수 있습니다.
예를 들어 아래에 속성 이있는 Message클래스가 author있습니다. Q_PROPERTY 매크로 호출 로 지정된 대로이 등록 정보는 author()메소드 를 통해 읽을 수 있으며 메소드를 통해 쓰기가 가능합니다 setAuthor().
class Message : public QObject { Q_OBJECT Q_PROPERTY(QString author READ author WRITE setAuthor NOTIFY authorChanged) public: void setAuthor(const QString &a) { if (a != m_author) { m_author = a; emit authorChanged(); } } QString author() const { return m_author; } signals: void authorChanged(); private: QString m_author; };
C++에서 명명 된 파일을로드 할 때이 클래스의 인스턴스가 컨텍스트 속성 으로 설정된 경우 MyItem.qml:
int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); QQuickView view; Message msg; view.engine()->rootContext()->setContextProperty("msg", &msg); view.setSource(QUrl::fromLocalFile("MyItem.qml")); view.show(); return app.exec(); }
그런 다음 author속성은 다음 위치에서 읽을 수 있습니다 MyItem.qml.
// MyItem.qml import QtQuick 2.0 Text { width: 100; height: 100 text: msg.author // invokes Message::author() to get this value Component.onCompleted: { msg.author = "Jonah" // invokes Message::setAuthor() } }
QML과의 최대 상호 운용성을 위해 쓰기 가능한 모든 속성 에는 속성 값이 변경 될 때마다 방출되는 관련 NOTIFY 신호가 있어야합니다 . 따라서 속성 바인딩을 사용할 때 속성 바인딩을 사용할 수 있습니다. 이 속성은 종속성의 값이 변경 될 때마다 속성을 자동으로 업데이트하여 속성 간의 관계를 적용하는 QML의 필수 기능입니다.
위의 예에서, author등록 정보에 대한 연관된 NOTIFY 신호 authorChanged는 Q_PROPERTY () 매크로 호출 에 지정된 대로 입니다. 즉, Message :: setAuthor ()에서 작성자가 변경 될 때와 같이 신호가 방출 될 때마다 QML 엔진에 author속성 과 관련된 모든 바인딩을 업데이트해야한다는 것을 알리고 엔진은 다음과 같이 text속성을 업데이트합니다. Message::author()다시 전화 .
author 속성이 쓰기 가능하지만 관련 NOTIFY 신호가없는 경우 Message::author()가 반환하는 초기 값으로 텍스트 값이 초기화되지만 나중에 이 속성을 변경하면 업데이트되지 않습니다. 또한 QML에서 속성에 바인딩하려는 시도는 엔진에서 런타임 경고를 생성합니다.
참고: NOTIFY 신호의 이름은 <property>Changed로 지정하는 것이 좋습니다. 여기서 <property>는 속성의 이름입니다. QML 엔진에 의해 생성 된 관련 속성 변경 신호 처리기는 관련 C++ 신호의 이름과 관계없이 항상 <Property>Changed의 형식을 취하므로 혼동을 피하기 위해 신호 이름이이 규칙을 따르는 것이 좋습니다.
Notes on Use of Notify Signals
루프 또는 과도한 평가를 방지하려면 개발자는 속성 값이 실제로 변경된 경우에만 속성 변경 신호가 방출되도록해야합니다. 또한 속성 또는 속성 그룹이 자주 사용되지 않으면 여러 속성에 대해 동일한 NOTIFY 신호를 사용할 수 있습니다. 성능이 저하되지 않도록주의해서 수행해야합니다.
NOTIFY 신호가 있으면 작은 오버 헤드가 발생합니다. 객체 생성시 속성 값이 설정되고 이후에 변경되지 않는 경우가 있습니다. 가장 일반적인 경우는 유형이 그룹화 된 속성을 사용하고 그룹화 된 속성 객체가 한 번 할당되며 객체가 삭제 될 때만 해제됩니다. 이 경우 CONSTANT 속성은 NOTIFY 신호 대신 속성 선언에 추가 될 수 있습니다.
CONSTANT 특성은 클래스 생성자에서만 값이 설정되고 완료되는 속성에만 사용해야합니다. 바인딩에 사용하려는 다른 모든 속성에는 NOTIFY 신호가 있어야합니다.
Properties with Object Types
오브젝트 유형 등록 정보는 QML 유형 시스템에 오브젝트 유형이 적절하게 등록 되어 있으면 QML에서 액세스 할 수 있습니다.
예를 들어 Message유형 의 유형이 다음과 같은 body속성을 가질 수 있습니다 MessageBody*.
class Message : public QObject { Q_OBJECT Q_PROPERTY(MessageBody* body READ body WRITE setBody NOTIFY bodyChanged) public: MessageBody* body() const; void setBody(MessageBody* body); }; class MessageBody : public QObject { Q_OBJECT Q_PROPERTY(QString text READ text WRITE text NOTIFY textChanged) // ... }
메시지 유형이 QML 유형 시스템에 등록되어 QML 코드의 객체 유형으로 사용될 수 있다고 가정합니다.
Message { // ... }
MessageBody 타입이 타입 시스템에도 등록되어 있다면, QML 코드 내에서 MessageBody를 Message의 body 속성에 할당 할 수 있습니다.
Message { body: MessageBody { text: "Hello, world!" } }
Properties with Object-List Types
QObject 파생 형식 목록을 포함하는 속성은 QML에 노출 될 수도 있습니다. 그러나이 목적을 위해 QList <T> 대신 속성 유형으로 QQmlListProperty를 사용해야합니다. 이는 QList가 QObject 파생 유형이 아니므로 Qt 메타 객체 시스템을 통해 필요한 QML 속성 특성을 제공 할 수 없기 때문입니다 (예 : 목록 수정시 신호 알림).
QQmlListProperty는 QList 값에서 편리하게 생성 할 수있는 템플릿 클래스입니다.
예를 들어 아래 MessageBoard 클래스에는 Message 인스턴스 목록을 저장하는 QQmlListProperty 유형의 messages 속성이 있습니다.
class MessageBoard : public QObject { Q_OBJECT Q_PROPERTY(QQmlListProperty<Message> messages READ messages) public: QQmlListProperty<Message> messages(); private: static void append_message(QQmlListProperty<Message> *list, Message *msg); QList<Message *> m_messages; };
MessageBoard::messages() 함수는 단순히 QQmlListProperty 생성자가 요구하는 적절한 목록 수정 함수를 전달하여 QList <T> m_messages 멤버에서 QQmlListProperty를 생성하고 반환합니다.
QQmlListProperty<Message> MessageBoard::messages() { return QQmlListProperty<Message>(this, 0, &MessageBoard::append_message); } void MessageBoard::append_message(QQmlListProperty<Message> *list, Message *msg) { MessageBoard *msgBoard = qobject_cast<MessageBoard *>(list->object); if (msg) msgBoard->m_messages.append(msg); }
QQmlListProperty (이 경우, Message)의 템플리트 클래스 유형은 QML 유형 시스템에 등록되어야합니다.
Grouped Properties
모든 읽기 전용 객체 유형 속성은 QML 코드에서 그룹화 된 속성으로 액세스 할 수 있습니다. 이것은 유형의 속성 집합을 설명하는 관련 속성 그룹을 공개하는 데 사용할 수 있습니다.
예를 들어, Message :: author 속성이 name 및 email 하위 속성을 가진 간단한 문자열이 아닌 MessageAuthor 유형이라고 가정합니다.
class MessageAuthor : public QObject { Q_PROPERTY(QString name READ name WRITE setName) Q_PROPERTY(QString email READ email WRITE setEmail) public: ... }; class Message : public QObject { Q_OBJECT Q_PROPERTY(MessageAuthor* author READ author) public: Message(QObject *parent) : QObject(parent), m_author(new MessageAuthor(this)) { } MessageAuthor *author() const { return m_author; } private: MessageAuthor *m_author; };
이 author속성은 다음 과 같이 QML의 그룹화 된 속성 구문을 사용하여 작성할 수 있습니다 .
Message { author.name: "Alexandra" author.email: "alexandra@mail.com" }
그룹화 된 속성으로 노출되는 유형 은 그룹화 된 속성이 읽기 전용이며 구성시 상위 개체에 의해 유효한 값으로 초기화된다는 점에서 개체 유형 속성 과 다릅니다. 그룹화 된 속성의 하위 속성은 QML에서 수정할 수 있지만 그룹화 된 속성 개체 자체는 절대로 변경되지 않지만 개체 유형 속성에는 언제든지 QML의 새 개체 값이 할당 될 수 있습니다. 따라서 그룹화 된 속성 개체의 수명은 C++ 부모 구현에 의해 엄격하게 제어되는 반면 개체 유형 속성은 QML 코드를 통해 자유롭게 만들어지고 파괴 될 수 있습니다.
Exposing Methods (Including Qt Slots)
다음과 같은 경우 QObject에서 파생 된 유형 의 모든 메소드에 QML 코드에서 액세스 할 수 있습니다.
> A public method flagged with the Q_INVOKABLE() macro
> A method that is a public Qt slot
예를 들어 아래의 MessageBoard 클래스에는 public 슬롯 인 refresh() 메서드뿐만 아니라 Q_INVOKABLE 매크로로 플래그 된 postMessage() 메서드가 있습니다.
class MessageBoard : public QObject { Q_OBJECT public: Q_INVOKABLE bool postMessage(const QString &msg) { qDebug() << "Called the C++ method with" << msg; return true; } public slots: void refresh() { qDebug() << "Called the C++ slot"; } };
MessageBoard의 인스턴스가 MyItem.qml 파일의 컨텍스트 데이터로 설정된 경우 MyItem.qml은 아래 예제와 같이 두 가지 메서드를 호출 할 수 있습니다.
C++ | int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); MessageBoard msgBoard; QQuickView view; view.engine()->rootContext()->setContextProperty("msgBoard", &msgBoard); view.setSource(QUrl::fromLocalFile("MyItem.qml")); view.show(); return app.exec(); } |
QML | // MyItem.qml import QtQuick 2.0 Item { width: 100; height: 100 MouseArea { anchors.fill: parent onClicked: { var result = msgBoard.postMessage("Hello from QML") console.log("Result of postMessage():", result) msgBoard.refresh(); } } } |
C++ 메소드에 QObject*유형이있는 매개 변수가있는 경우 객체 id를 참조하는 JavaScript var 값 또는 객체를 사용하여 QML 에서 매개 변수 값을 전달할 수 있습니다.
QML은 오버로드 된 C++ 함수 호출을 지원합니다. 같은 이름이지만 다른 인수를 가진 여러 C++ 함수가있는 경우 제공되는 인수의 수와 유형에 따라 올바른 함수가 호출됩니다.
QML의 JavaScript 표현식에서 액세스 할 때 C++ 메소드에서 반환 된 값은 JavaScript 값으로 변환됩니다.
Exposing Signals
QObject 파생 형식의 공용 신호는 QML 코드에서 액세스 할 수 있습니다.
QML 엔진은 QML에서 사용되는 QObject 파생 형식의 신호에 대한 신호 처리기를 자동으로 만듭니다. 신호 핸들러는 항상 <Signal>에 명명됩니다. 여기서 <Signal>은 첫 번째 문자를 대문자로 사용하여 신호 이름입니다. 신호에 의해 전달 된 모든 매개 변수는 매개 변수 이름을 통해 신호 처리기에서 사용할 수 있습니다.
예를 들어 MessageBoard 클래스에 subject라는 단일 매개 변수가있는 newMessagePosted() 신호가 있다고 가정합니다.
class MessageBoard : public QObject { Q_OBJECT public: // ... signals: void newMessagePosted(const QString &subject); };
MessageBoard 유형이 QML 유형 시스템에 등록 된 경우 QML에 선언 된 MessageBoard 객체는 onNewMessagePosted라는 신호 처리기를 사용하여 newMessagePosted () 신호를 수신하고 subject 매개 변수 값을 검사 할 수 있습니다.
MessageBoard { onNewMessagePosted: console.log("New message received:", subject) }
속성 값 및 메서드 매개 변수와 마찬가지로 신호 매개 변수는 QML 엔진에서 지원하는 형식이어야 합니다. QML과 C++ 간의 데이터 형식 변환을 참조하십시오. 등록되지 않은 유형을 사용하더라도 오류는 발생하지 않지만 매개 변수 값은 처리기에서 액세스 할 수 없습니다.
클래스는 동일한 이름의 다중 신호를 가질 수 있지만 최종 신호 만 QML 신호로 액세스 할 수 있습니다. 이름은 같지만 매개 변수가 다른 신호는 서로 구별 할 수 없습니다.
'Qt' 카테고리의 다른 글
Embedding C++ Objects into QML with Context Properties (0) | 2017.06.11 |
---|---|
Defining QML Types from C++ (0) | 2017.06.10 |
Intergrating QML and C++ (0) | 2017.06.10 |
[발번역] Performance Considerations And Suggestions (0) | 2017.05.15 |
[발번역] QML Canvas Element (0) | 2017.02.22 |