Qt?Qml實現(xiàn)任意角為圓角的矩形
在 Qml 中,矩形(Rectangle)是最常用的元素之一。
然而,標準的矩形元素僅允許設(shè)置統(tǒng)一的圓角半徑。
在實際開發(fā)中,我們經(jīng)常需要更靈活的圓角設(shè)置,例如只對某些角進行圓角處理,或者設(shè)置不同角的圓角半徑。
本文將介紹如何通過自定義 Qml 元素實現(xiàn)一個任意角可為圓角的矩形。
效果圖

自定義 Qml 元素:DelRectangle
我們將創(chuàng)建一個名為 DelRectangle 的自定義 Qml 元素,它繼承自 QQuickPaintedItem,并重寫其 paint() 方法來自定義繪制邏輯。
頭文件(delrectangle.h)
#ifndef DELRECTANGLE_H
#define DELRECTANGLE_H
#include <QQuickPaintedItem>
class DelPen: public QObject
{
Q_OBJECT
Q_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_OBJECT
Q_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
實現(xiàn)文件(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();
}
關(guān)鍵點解析
自定義 Qml 元素:通過繼承 QQuickPaintedItem 并使用 QML_NAMED_ELEMENT 宏,我們可以將自定義的 C++ 類注冊為 Qml 元素。
屬性定義:我們定義了多個屬性來控制矩形的圓角半徑和顏色,例如 radius、topLeftRadius、color 等,并提供了相應(yīng)的 getter 和 setter 方法。
邊框管理:通過 DelPen 類來管理矩形的邊框樣式,包括邊框顏色和寬度。
繪制邏輯:在 paint() 方法中,我們使用 QPainterPath 來繪制具有不同圓角的矩形。通過組合使用直線和弧線,我們可以實現(xiàn)任意角的圓角效果。
使用示例
在 Qml 文件中,我們可以像使用標準的 Rectangle 元素一樣使用 DelRectangle:
import QtQuick 2.15
import QtQuick.Window 2.15
import DelegateUI.Controls 1.0
Window {
visible: true
width: 400
height: 300
title: "DelRectangle Example"
DelRectangle {
anchors.centerIn: parent
width: 200
height: 150
color: "lightblue"
topLeftRadius: 20
bottomRightRadius: 30
border {
width: 2
color: "blue"
}
}
}
總結(jié)
通過自定義 Qml 元素 DelRectangle,我們實現(xiàn)了對矩形圓角的更靈活控制,使其能夠滿足更多實際開發(fā)需求。
要注意的是,在 Qt 6.7 版本以后,內(nèi)置的 Rectangle 將提供同等功能( 作為技術(shù)預(yù)覽 ),并且效果更好:

到此這篇關(guān)于Qt Qml實現(xiàn)任意角為圓角的矩形的文章就介紹到這了,更多相關(guān)Qt Qml圓角矩形內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

