qml
Aangepaste elementen maken in C ++
Zoeken…
Aangepaste elementen maken in C ++
QML kwam met een rijke set visuele elementen. Met alleen QML kunnen we complexe applicaties bouwen met deze elementen. Het is ook heel gemakkelijk om je eigen element te bouwen op basis van een reeks standaarditems zoals Rechthoek, Knop, Afbeelding enz. Bovendien kunnen we items zoals Canvas gebruiken om een element met een aangepast schilderij te bouwen. Het lijkt erop dat we een verscheidenheid aan applicaties alleen in QML kunnen bouwen, zonder de mogelijkheden van C ++ aan te raken. En het is eigenlijk waar, maar soms willen we onze applicatie sneller maken of willen we deze uitbreiden met de kracht van Qt of een aantal mogelijkheden toevoegen die niet beschikbaar zijn in QML. En zeker is er een dergelijke mogelijkheid in QML . In feite gebruikt QtQuick Scene Graph om de inhoud ervan te schilderen als een krachtige rendering-engine op basis van OpenGL . Om ons eigen visuele element te implementeren, kunnen we 2 manieren gebruiken:
- De traditionele manier voor Qt met QPainter ( QQuickPaintedItem ).
- De algemene QML-manier met behulp van QQuickItem en OpenGL-functionaliteit.
Het is mogelijk dat de eerste methode eenvoudiger lijkt, maar het is de moeite waard om te overwegen dat deze ook langzamer is dan de eerste, aangezien QtQuick de inhoud van het item op een oppervlak schildert en het vervolgens in een scènegrafiek invoegt, zodat de weergave in twee stappen verloopt. Dus het gebruik van scene graph API is altijd aanzienlijk sneller.
Laten we, om beide methoden nader te onderzoeken, ons eigen element maken dat absoluut niet bestaat in QML, bijvoorbeeld een driehoek.
Klasse verklaring
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();
};
We voegen de macro Q_OBJECT toe om met signalen te werken. Ook voegen we aangepaste eigenschappen toe om de kleur van onze rechthoek te specificeren. Om het te laten werken, is alles wat we nodig hebben de virtuele functie QQuiclItem :: updatePaintNode () opnieuw implementeren.
Klasse implementatie.
Eerst definiëren we een constructor.
QQuickCustomItem::QQuickCustomItem(QQuickItem *parent) :
QQuickItem(parent),
m_color(Qt::red),
m_needUpdate(true)
{
setFlag(QQuickItem::ItemHasContents);
}
Houd er rekening mee dat de functieaanroep setFlag () verplicht is, anders wordt uw object niet aan de scènegrafiek toegevoegd. Vervolgens definiëren we een functie voor de pijn.
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;
}
Bij de eerste aanroep van de functie is ons knooppunt nog niet gemaakt, dus oldNode wordt NULL. Dus maken we de knoop en wijzen er geometrie en materiaal aan toe. Hier gebruiken we GL_TRIANGLE_FAN voor onze geometrie om een solide rechthoek te schilderen. Dit punt is hetzelfde als in OpenGL. Om bijvoorbeeld een driehoekig kader te tekenen, kunnen we de code wijzigen in:
geometry->setDrawingMode(GL_LINE_LOOP);
geometry->setLineWidth(5);
U kunt de OpenGL- handleiding raadplegen om te controleren op andere vormen. Dus, het enige dat overblijft is om setter / getter voor ons eigendom te definiëren:
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();
}
}
Nu is er slechts één klein detail om het te laten werken. We moeten QtQuick op de hoogte stellen van het nieuwe item. U kunt deze code bijvoorbeeld toevoegen aan uw main.cpp:
qmlRegisterType<QQuickCustomItem>("stackoverflow.qml", 1, 0, "Triangle");
En hier is ons QML-testbestand:
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);
}
}
Zoals u ziet, gedraagt ons item zich als alle andere QML-items. Laten we nu hetzelfde item maken met QPainter :
Alles wat we nodig hebben is om te vervangen
QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData);
met
void paint(QPainter *painter);
en, erven onze klasse van QQuickPaintedItem plaats van QQuickItem . Hier is onze schilderfunctie:
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);
}
Al het andere blijft ongewijzigd.