수색…


C ++에서 사용자 정의 요소 만들기

QML에는 다양한 시각적 요소가있었습니다. QML 만 사용하여 이러한 요소로 복잡한 응용 프로그램을 작성할 수 있습니다. 또한 Rectangle, Button, Image 등과 같은 표준 항목 세트를 기반으로 자신 만의 요소를 만드는 것도 매우 쉽습니다. 또한 Canvas와 같은 항목을 사용하여 사용자 정의 그림을 사용하여 요소를 작성할 수 있습니다. 우리는 C ++의 기능에 손대지 않고도 QML로만 다양한 애플리케이션을 구축 할 수 있습니다. 실제로는 사실이지만 때로는 애플리케이션을 더 빠르게 만들고 싶거나 Qt를 사용하여 확장하거나 QML에서 사용할 수없는 기회를 추가하려고합니다. QML 에는 이러한 가능성이 있습니다. 기본적으로 QtQuick장면 그래프 를 사용하여 OpenGL을 기반으로 하는 고성능 렌더링 엔진의 컨텐츠를 그립니다. 우리 자신의 시각적 요소를 구현하기 위해 다음 두 가지 방법을 사용할 수 있습니다.

  1. QPainter ( QQuickPaintedItem )를 사용하는 전통적인 Qt 방식.
  2. QQuickItem 과 OpenGL 기능을 사용하는 일반적인 QML 방식.

첫 번째 방법이 더 쉬울 수도 있지만 QtQuick이 항목의 내용을 표면에 칠한 다음 씬 그래프에 삽입하여 렌더링이 두 단계로 이루어지기 때문에 첫 번째 방법보다 느린 것을 고려해 볼 가치가 있습니다. 따라서 장면 그래프 API를 직접 사용하는 것이 항상 훨씬 빠릅니다.

두 가지 방법을 모두 탐구하기 위해 QML에 존재하지 않는 요소, 예를 들어 삼각형을 만들자.

클래스 선언

class QQuickCustomItem : public QQuickItem
{
    Q_OBJECT
    Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
public:
    QQuickCustomItem(QQuickItem *parent = Q_NULLPTR);

protected:
    QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData);

    QColor color() const;
    void setColor(const QColor &color);

private:
    QColor m_color;
    bool m_needUpdate;

signals:
    void colorChanged();
};

Q_OBJECT 매크로를 추가하여 신호를 처리합니다. 또한 사용자 정의 속성을 추가하여 Rectangle의 색상을 지정합니다. 이 함수가 제대로 작동하게하려면 가상 함수 QQuiclItem :: updatePaintNode ()를 다시 구현해야합니다.

클래스 구현.

먼저 생성자를 정의합니다.

QQuickCustomItem::QQuickCustomItem(QQuickItem *parent) :
    QQuickItem(parent),
    m_color(Qt::red),
    m_needUpdate(true)
{
    setFlag(QQuickItem::ItemHasContents);
}

setFlag () 함수 호출은 필수입니다. 그렇지 않으면 객체가 장면 그래프에 추가되지 않습니다. 다음으로, 우리는 paining을위한 함수를 정의한다.

QSGNode *QQuickCustomItem::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *updatePaintNodeData)
{
    Q_UNUSED(updatePaintNodeData)
    QSGGeometryNode *root = static_cast<QSGGeometryNode *>(oldNode);

    if(!root) {
        root = new QSGGeometryNode;
        QSGGeometry *geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 3);
        geometry->setDrawingMode(GL_TRIANGLE_FAN);
        geometry->vertexDataAsPoint2D()[0].set(width() / 2, 0);
        geometry->vertexDataAsPoint2D()[1].set(width(), height());
        geometry->vertexDataAsPoint2D()[2].set(0, height());

        root->setGeometry(geometry);
        root->setFlag(QSGNode::OwnsGeometry);
        root->setFlag(QSGNode::OwnsMaterial);
    }

    if(m_needUpdate) {
        QSGFlatColorMaterial *material = new QSGFlatColorMaterial;
        material->setColor(m_color);
        root->setMaterial(material);
        m_needUpdate = false;
    }

    return root;
}

함수에 대한 첫 번째 호출에서 우리 노드는 아직 생성되지 않았으므로 oldNode 는 NULL이됩니다. 그래서 우리는 노드를 만들고 그것에 기하학과 재료를 할당합니다. 여기서 GL_TRIANGLE_FAN 을 사용하여 솔리드 직사각형을 그릴 수 있습니다. 이 점은 OpenGL에서와 동일합니다. 예를 들어 삼각형 프레임을 그리려면 코드를 다음과 같이 변경할 수 있습니다.

geometry->setDrawingMode(GL_LINE_LOOP);
geometry->setLineWidth(5);

OpenGL 설명서를 참조하여 다른 모양을 확인할 수 있습니다. 그래서 남아있는 것은 우리의 속성에 대한 setter / getter를 정의하는 것입니다.

QColor QQuickCustomItem::color() const
{
    return m_color;
}

void QQuickCustomItem::setColor(const QColor &color)
{
    if(m_color != color) {
        m_color = color;
        m_needUpdate = true;
        update();
        colorChanged();
    }
}

이제는 작은 세부 사항 만 있으면 작동합니다. 우리는 새 항목에 대해 QtQuick 에 알릴 필요가 있습니다. 예를 들어 main.cpp에 다음 코드를 추가 할 수 있습니다.

qmlRegisterType<QQuickCustomItem>("stackoverflow.qml", 1, 0, "Triangle");

QML 테스트 파일은 다음과 같습니다.

import QtQuick 2.7
import QtQuick.Window 2.0
import stackoverflow.qml 1.0

Window {
    width: 800
    height: 800
    visible: true

    Rectangle {
        width: 200
        height: 200
        anchors.centerIn: parent
        color: "lightgrey"

        Triangle {
            id: rect
            width: 200
            height: 200
            transformOrigin: Item.Top
            color: "green"
            onColorChanged: console.log("color was changed");
            PropertyAnimation on rotation {
                from: 0
                to: 360
                duration: 5000
                loops: Animation.Infinite
            }
        }
    }
    Timer {
        interval: 1000
        repeat: true
        running: true
        onTriggered: rect.color = Qt.rgba(Math.random(),Math.random(),Math.random(),1);
    }
}

보시다시피, 우리의 아이템은 다른 모든 QML 아이템처럼 동작합니다. 이제 QPainter를 사용하여 동일한 항목을 만듭니다.

우리가 필요로하는 것은

QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData);

void paint(QPainter *painter);

그리고, 우리는 클래스를 QQuickPaintedItem 대신 QQuickItem 에서 상속받습니다. 여기에 그림 기능이 있습니다.

void QQuickCustomItem::paint(QPainter *painter)
{
    QPainterPath path;
    path.moveTo(width() / 2, 0);
    path.lineTo(width(), height());
    path.lineTo(0, height());
    path.lineTo(width() / 2, 0);
    painter->fillPath(path, m_color);
}

나머지는 변경되지 않습니다.



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow