qml
C ++でのカスタム要素の作成
サーチ…
C ++でのカスタム要素の作成
QMLには豊富なビジュアル要素が付属していました。 QMLだけを使用して、これらの要素で複雑なアプリケーションを構築できます。また、Rectangle、Button、Imageなどの標準アイテムのセットに基づいて独自の要素を作成するのはとても簡単です。さらに、Canvasのようなアイテムを使用してカスタムペイントで要素を作成することもできます。 C ++の機能に触れることなく、QMLでのみさまざまなアプリケーションを構築できるようです。実際には真実ですが、アプリケーションをより速くしたい場合や、Qtの力で拡張したい場合や、QMLで利用できない機会を追加したい場合もあります。 QMLには確かにそのような可能性があります。基本的にQtQuickは、 シーングラフを使用してOpenGLに基づく高性能レンダリングエンジンのコンテンツをペイントします 。独自のビジュアル要素を実装するには、2つの方法があります。
- 使用してQtの道のための伝統的なQPainterの ( QQuickPaintedItemを )。
- QQuickItemとOpenGLの機能を使った一般的なQML方法。
QtQuickはアイテムのコンテンツをサーフェス上にペイントしてシーングラフに挿入してレンダリングを2段階で実行するため、最初のメソッドは簡単に見える可能性がありますが、最初のメソッドよりも遅いことも考慮する必要があります。したがって、シーングラフ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()関数呼び出しは必須です。そうでない場合、オブジェクトはシーングラフに追加されません。次に、ペインティングのための関数を定義します。
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のマニュアルを参照して他の図形をチェックすることができます。だから、残っているのは、私たちのプロパティのセッター/ゲッターを定義することです:
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();
}
}
今はそれを動作させるための小さな細部が1つしかありません。新しいアイテムについて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クラスは、 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);
}
他のすべては変更されません。