【写在前面】
在 Qml 中,矩形(Rectangle)是最常用的元素之一。
然而,标准的矩形元素仅允许设置统一的圆角半径。
在实际开发中,我们经常需要更灵活的圆角设置,例如只对某些角进行圆角处理,或者设置不同角的圆角半径。
本文将介绍如何通过自定义 Qml 元素实现一个任意角可为圆角的矩形。
【正文开始】
效果图
自定义 Qml 元素:DelRectangle
我们将创建一个名为 DelRectangle
的自定义 Qml 元素,它继承自 QQuickPaintedItem
,并重写其 paint()
方法来自定义绘制逻辑。
头文件(delrectangle.h)
#ifndef DELRECTANGLE_H
#define DELRECTANGLE_H#include <QQuickPaintedItem>class DelPen: public QObject
{Q_OBJECTQ_PROPERTY(qreal width READ width WRITE setWidth NOTIFY widthChanged FINAL)Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged FINAL)QML_NAMED_ELEMENT(DelPen)
public:DelPen(QObject *parent = nullptr);qreal width() const;void setWidth(qreal width);QColor color() const;void setColor(const QColor &color);bool isValid() const;
signals:void widthChanged();void colorChanged();
private:qreal m_width = 1;QColor m_color = Qt::transparent;
};class DelRectangle: public QQuickPaintedItem
{Q_OBJECTQ_PROPERTY(qreal radius READ radius WRITE setRadius NOTIFY radiusChanged FINAL)Q_PROPERTY(qreal topLeftRadius READ topLeftRadius WRITE setTopLeftRadius NOTIFY topLeftRadiusChanged FINAL)Q_PROPERTY(qreal topRightRadius READ topRightRadius WRITE setTopRightRadius NOTIFY topRightRadiusChanged FINAL)Q_PROPERTY(qreal bottomLeftRadius READ bottomLeftRadius WRITE setBottomLeftRadius NOTIFY bottomLeftRadiusChanged FINAL)Q_PROPERTY(qreal bottomRightRadius READ bottomRightRadius WRITE setBottomRightRadius NOTIFY bottomRightRadiusChanged FINAL)Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged FINAL)Q_PROPERTY(DelPen* border READ border CONSTANT)QML_NAMED_ELEMENT(DelRectangle)
public:explicit DelRectangle(QQuickItem *parent = nullptr);~DelRectangle();qreal radius() const;void setRadius(qreal radius);qreal topLeftRadius() const;void setTopLeftRadius(qreal radius);qreal topRightRadius() const;void setTopRightRadius(qreal radius);qreal bottomLeftRadius() const;void setBottomLeftRadius(qreal radius);qreal bottomRightRadius() const;void setBottomRightRadius(qreal radius);QColor color() const;void setColor(QColor color);DelPen *border();void paint(QPainter *painter) override;
signals:void radiusChanged();void topLeftRadiusChanged();void topRightRadiusChanged();void bottomLeftRadiusChanged();void bottomRightRadiusChanged();void colorChanged();
private:Q_DECLARE_PRIVATE(DelRectangle);QSharedPointer<DelRectanglePrivate> d_ptr;
};#endif // DELRECTANGLE_H
实现文件(delrectangle.cpp)
#include "delrectangle.h"#include <QPainter>
#include <QPainterPath>
#include <private/qqmlglobal_p.h>class DelRectanglePrivate
{
public:QColor m_color = { 0xffffff };DelPen *m_pen = nullptr;qreal m_radius = 0;qreal m_topLeftRadius = 0;qreal m_topRightRadius = 0;qreal m_bottomLeftRadius = 0;qreal m_bottomRightRadius = 0;
};DelRectangle::DelRectangle(QQuickItem *parent): QQuickPaintedItem{parent}, d_ptr(new DelRectanglePrivate)
{
}DelRectangle::~DelRectangle()
{
}qreal DelRectangle::radius() const
{Q_D(const DelRectangle);return d->m_radius;
}void DelRectangle::setRadius(qreal radius)
{Q_D(DelRectangle);if (d->m_radius != radius) {d->m_radius = radius;d->m_topLeftRadius = radius;d->m_topRightRadius = radius;d->m_bottomLeftRadius = radius;d->m_bottomRightRadius = radius;emit radiusChanged();update();}
}// 其他 getter 和 setter 方法省略...QColor DelRectangle::color() const
{Q_D(const DelRectangle);return d->m_color;
}void DelRectangle::setColor(QColor color)
{Q_D(DelRectangle);if (d->m_color != color) {d->m_color = color;emit colorChanged();update();}
}DelPen *DelRectangle::border()
{Q_D(DelRectangle);if (!d->m_pen) {d->m_pen = new DelPen;QQml_setParent_noEvent(d->m_pen, this);connect(d->m_pen, &DelPen::colorChanged, this, [this]{ update(); });connect(d->m_pen, &DelPen::widthChanged, this, [this]{ update(); });update();}return d->m_pen;
}void DelRectangle::paint(QPainter *painter)
{Q_D(DelRectangle);painter->save();painter->setRenderHint(QPainter::Antialiasing);QRectF rect = boundingRect();if (d->m_pen && d->m_pen->isValid()) {rect = boundingRect();if (rect.width() > d->m_pen->width() * 2) {auto dx = d->m_pen->width() * 0.5;rect.adjust(dx, 0, -dx, 0);}if (rect.height() > d->m_pen->width() * 2) {auto dy = d->m_pen->width() * 0.5;rect.adjust(0, dy, 0, -dy);}painter->setPen(QPen(d->m_pen->color(), d->m_pen->width(), Qt::SolidLine, Qt::SquareCap, Qt::SvgMiterJoin));}QPainterPath path;path.moveTo(rect.bottomRight() - QPointF(0, d->m_bottomRightRadius));path.lineTo(rect.topRight() + QPointF(0, d->m_topRightRadius));path.arcTo(QRectF(QPointF(rect.topRight() - QPointF(d->m_topRightRadius * 2, 0)), QSize(d->m_topRightRadius * 2, d->m_topRightRadius * 2)), 0, 90);path.lineTo(rect.topLeft() + QPointF(d->m_topLeftRadius, 0));path.arcTo(QRectF(QPointF(rect.topLeft()), QSize(d->m_topLeftRadius * 2, d->m_topLeftRadius * 2)), 90, 90);path.lineTo(rect.bottomLeft() - QPointF(0, d->m_bottomLeftRadius));path.arcTo(QRectF(QPointF(rect.bottomLeft().x(), rect.bottomLeft().y() - d->m_bottomLeftRadius * 2), QSize(d->m_bottomLeftRadius * 2, d->m_bottomLeftRadius * 2)), 180, 90);path.lineTo(rect.bottomRight() - QPointF(d->m_bottomRightRadius, 0));path.arcTo(QRectF(QPointF(rect.bottomRight() - QPointF(d->m_bottomRightRadius * 2, d->m_bottomRightRadius * 2)), QSize(d->m_bottomRightRadius * 2, d->m_bottomRightRadius * 2)), 270, 90);painter->setBrush(d->m_color);painter->drawPath(path);painter->restore();
}
关键点解析
-
自定义 Qml 元素:通过继承
QQuickPaintedItem
并使用QML_NAMED_ELEMENT
宏,我们可以将自定义的 C++ 类注册为 Qml 元素。 -
属性定义:我们定义了多个属性来控制矩形的圆角半径和颜色,例如
radius
、topLeftRadius
、color
等,并提供了相应的 getter 和 setter 方法。 -
边框管理:通过
DelPen
类来管理矩形的边框样式,包括边框颜色和宽度。 -
绘制逻辑:在
paint()
方法中,我们使用QPainterPath
来绘制具有不同圆角的矩形。通过组合使用直线和弧线,我们可以实现任意角的圆角效果。
使用示例
在 Qml 文件中,我们可以像使用标准的 Rectangle
元素一样使用 DelRectangle
:
import QtQuick 2.15
import QtQuick.Window 2.15
import DelegateUI.Controls 1.0Window {visible: truewidth: 400height: 300title: "DelRectangle Example"DelRectangle {anchors.centerIn: parentwidth: 200height: 150color: "lightblue"topLeftRadius: 20bottomRightRadius: 30border {width: 2color: "blue"}}
}
总结
通过自定义 Qml 元素 DelRectangle
,我们实现了对矩形圆角的更灵活控制,使其能够满足更多实际开发需求。
要注意的是,在 Qt 6.7 版本以后,内置的 Rectangle
将提供同等功能( 作为技术预览 ),并且效果更好:
最后:项目链接(多多star呀..⭐_⭐):
Github: https://github.com/mengps/QmlControls
Gitee: https://gitee.com/MenPenS/QmlControls