往期回顾
Qt绘图与图形视图之绘制带三角形箭头的窗口的简单介绍
一、最终效果
点击pushbutton按钮,弹出一个带三角形的对话框,其三角形正好就在按钮正中心下方
二、设计思路
需要考虑两个问题:
1、这个对话框怎么画,才能够有这种效果,矩形上冒出个小三角形;
2、如何精准找到这个位置,让其准确显示在按钮下方;
3、对话框的设计
三、具体设计实现
1、对话框怎么画
这里由于是点击按钮弹出,所以对话框是继承自对话框类Dialog,主要抓住几个关键点,三角形的起始位置和底边长、高度。
1.1、setTriangleInfo函数
setTriangleInfo函数用于设置小三角形的起始位置、宽度和高度,以便在对话框绘制时使用。
其中涉及到一个explicit关键字:
在C++中,explicit关键字用于声明一个构造函数为显式构造函数。当一个构造函数被声明为explicit时,它将禁止隐式转换和复制初始化。这意味着在使用该构造函数创建对象时,必须显式调用构造函数,而不能通过隐式转换或复制初始化来创建对象。这样做可以避免一些意外的类型转换,提高代码的可读性和安全性。
/*
带三角形箭头的对话框
*/
#ifndef TRIANGLEDIALOG_H
#define TRIANGLEDIALOG_H
#include <QDialog>
class TriangleDialog : public QDialog
{
Q_OBJECT
public:
explicit TriangleDialog(int fixedW, int fixedH, QWidget *parent = nullptr);
// 设置小三角行的起始位置、宽、高
void setTriangleInfo(int startX, int width, int height);
protected:
void paintEvent(QPaintEvent *e);
private:
// 小三角形的起始位置
int m_startX;
// 小三角形的宽度
int m_triangleWidth;
// 小三角形的高度
int m_triangleHeight;
};
#endif // TRIANGLEDIALOG_H
1.2、对关键参数直接宏定义
#define SHADOW_WIDTH 15 // 窗口阴影宽度
#define TRIANGLE_WIDTH 15 // 小三角行的宽度
#define TRIANGLE_HEIGHT 10 // 小三角行的高度
#define BORDER_RADIUS 5 // 窗口圆角
1.3、设置对话框的窗口标志
setWindowFlags(Qt::FramelessWindowHint | Qt::Popup | Qt::NoDropShadowWindowHint);
setAttribute(Qt::WA_TranslucentBackground); // 设置透明窗口, 为窗口阴影和圆角做准备
几个注意点:
Qt::FramelessWindowHint: | 表示对话框没有窗口边框和标题栏,即无边框窗口。 |
Qt::Popup: | 表示对话框是一个弹出式窗口,通常用于弹出式菜单或提示框。 |
Qt::NoDropShadowWindowHint: | 表示对话框不显示窗口阴影效果。 |
1.4、设置布局的四周边距
参数是左上右下,除了上需要加上三角形的高之外,其他都一样的大小,直接用15
pVlay->setContentsMargins(SHADOW_WIDTH, SHADOW_WIDTH + TRIANGLE_HEIGHT, SHADOW_WIDTH, SHADOW_WIDTH);
1.5、设置阴影效果
setGraphicsEffect(QGraphicsEffect *effect):
这个方法用于为一个窗口部件设置图形效果。可以通过传入一个QGraphicsEffect对象来实现各种特效,比如阴影、模糊等。这个方法可以让窗口部件呈现出更加生动和美观的效果。
// 设置阴影边框
auto shadowEffect = new QGraphicsDropShadowEffect(this);
shadowEffect->setOffset(0, 0);
shadowEffect->setColor(Qt::red);
shadowEffect->setBlurRadius(SHADOW_WIDTH);
//setGraphicsEffect(QGraphicsEffect *effect):用于为一个窗口部件设置图形效果
this->setGraphicsEffect(shadowEffect);
1.6、重写paintEvent方法
1.6.1、代码示例
void TriangleDialog::paintEvent(QPaintEvent *e)
{
QPainter painter(this);
//setRenderHint(QPainter::RenderHint hint, bool on = true):用于设置绘图时的渲染提示
//hint参数表示要设置的渲染提示,比如抗锯齿、文本抗锯齿等。on参数表示是否开启这个渲染提示
painter.setRenderHint(QPainter::Antialiasing, true);
painter.setPen(Qt::NoPen); //将画笔设置为无边框
painter.setBrush(QColor(55, 55, 55)); //设置画刷颜色为灰色
// 小三角区域,这里是等腰三角形
//小三角形的三个点的坐标,注意不要忘记窗口边距就行
QPolygon trianglePolygon;
trianglePolygon << QPoint(m_startX, m_triangleHeight + SHADOW_WIDTH);
trianglePolygon << QPoint(m_startX + m_triangleWidth / 2, SHADOW_WIDTH);
trianglePolygon << QPoint(m_startX + m_triangleWidth, m_triangleHeight + SHADOW_WIDTH);
QPainterPath drawPath; //用于定义整个绘制路径
//调用 drawPath.addRoundedRect 方法添加一个带有圆角的矩形路径,用于绘制矩形框的主体部分。
// 圆角的半径由 BORDER_RADIUS 定义
//addRoundedRect(const QRectF &rect, qreal xRadius, qreal yRadius):用于在绘图路径中添加一个带有圆角的矩形
drawPath.addRoundedRect(QRect(SHADOW_WIDTH, SHADOW_WIDTH + m_triangleHeight,
this->width() - SHADOW_WIDTH * 2, this->height() - SHADOW_WIDTH * 2 - m_triangleHeight),
BORDER_RADIUS, BORDER_RADIUS);
// 矩形路径加上三角形
//addPolygon(const QPolygonF &polygon):用于在绘图路径中添加一个多边形
//polygon参数表示要添加的多边形的顶点坐标
drawPath.addPolygon(trianglePolygon);
// 绘制整个路径
painter.drawPath(drawPath);
}
1.6.2、代码执行思路
其实是很简单的,我们只需要指出小三角形的三个点位置,然后添加进去拿给painter.drawPath,他自己会画好
具体思路:
(1)首先创建了一个 QPainter 对象 painter,将画笔设置为无边框, 画刷颜色设置为灰色
(2)然后创建了一个QPolygon对象trianglePolygon,用于定义小三角形的顶点坐标。
(3)接着创建了一个 QPainterPath 对象 drawPath,用于定义整个绘制路径。
(4)调用drawPath.addRoundedRect方法添加一个带有圆角的矩形路径,用于绘制矩形框的主体部分。
(5)圆角的半径由 BORDER_RADIUS 定义。
(6)调用 drawPath.addPolygon 方法将小三角形的路径添加到整个绘制路径中。
(7)最后调用 painter.drawPath(drawPath) 方法来绘制整个路径,包括带有圆角的矩形和小三角形。
1.6.3、QPolygon类
QPolygon是Qt中用于表示多边形的类,它可以用来表示一个多边形的顶点坐标。它提供了方便的接口来操作多边形,可以用于绘制各种形状的图形,进行碰撞检测等操作。
1.6.3.1、构造函数:
QPolygon(): | 创建一个空的多边形。 |
QPolygon(const QPolygon &other): | 使用另一个 QPolygon 对象来初始化新的多边形。 |
QPolygon(const QVector<QPoint> &points): | 使用给定的点集合来初始化新的多边形。 |
1.6.3.2、成员函数:
void << (const QPoint &point): | 向多边形中添加一个顶点。 |
int size() const: | 返回多边形中顶点的个数。 |
QPoint at(int i) const: | 返回多边形中第 i 个顶点的坐标。 |
void setPoint(int i, const QPoint &point): | 设置多边形中第 i 个顶点的坐标。 |
bool containsPoint(const QPoint &point, Qt::FillRule fillRule = Qt::OddEvenFill) const: | 检查给定的点是否在多边形内部。 |
QRect boundingRect() const: | 返回包围多边形的最小矩形区域。 |
1.6.3.3、使用场景:
绘制不规则图形: | 通过定义多边形的顶点坐标,可以绘制各种不规则形状的图形。 |
碰撞检测: | 可以使用 containsPoint 方法来检查一个点是否在多边形内部,用于碰撞检测等应用场景。 |
图形处理: | 在图形处理和绘图应用中,多边形常用于定义复杂的图形形状。 |
1.6.4、几个难懂的方法
1.6.4.1、
setRenderHint(QPainter::RenderHint hint, bool on = true):
这个方法用于设置绘图时的渲染提示。hint参数表示要设置的渲染提示,比如抗锯齿、文本抗锯齿等。on参数表示是否开启这个渲染提示。通过设置不同的渲染提示,可以优化绘图的效果和性能。
1.6.4.2、
addRoundedRect(const QRectF &rect, qreal xRadius, qreal yRadius):
这个方法用于在绘图路径中添加一个带有圆角的矩形。rect参数表示矩形的位置和大小,xRadius和yRadius参数表示矩形的水平和垂直方向的圆角半径。这个方法常用于绘制带有圆角的界面元素,比如圆角按钮、对话框等。
1.6.4.3、
addPolygon(const QPolygonF &polygon):
这个方法用于在绘图路径中添加一个多边形。polygon参数表示要添加的多边形的顶点坐标。通过添加多边形,可以在绘图中绘制各种复杂的形状。
2、如何准确找到对话框弹出的位置
看这个之前要想清楚一个问题,这个对话框弹出的位置不是相对于widget窗口而言的,不能以窗口的(0,0)到对话框的位置大小来当作其坐标。
2.1、思路
重点在于,要找到三角形所在对话框的左上角位置,通过画图思考:
2.1.1、X位置
其实想通了很简单,x就是按钮的左上角x+按钮宽度一半-三角形起始点的x-三角形底边一半的宽
int x = p1.x() + rect1.width() / 2 - triangle_start_x - 20 / 2;
如果想不通,就简单化,从最终效果来看,按钮的x本来和对话框x就是一样大的(这个画的图有问题,看最终效果图),但是要减去一个窗口边距
所以直接:int x = p1.x() - 15;
结果也是正确的
2.1.2、Y位置
这个就更好想了,按钮的起始点y+按钮本身高度-窗口边距15
多减一是因为不想贴合太紧
int y = p1.y() + rect1.height() + 1 - 15;
3、对话框设计
这个我们应该是已经很熟悉了,没啥好说的,大家看看就行
#include "userinfowidget.h"
#include "ui_userinfowidget.h"
UserInfoWidget::UserInfoWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::UserInfoWidget)
{
ui->setupUi(this);
setFixedSize(this->width(), this->height());
setAttribute(Qt::WA_StyledBackground);
QString qss = "QLabel{font-family:Microsoft YaHei; font-size:18px; color:#ffffff; background-color:#363636;}";
ui->label_UserImage->setText("");
QPixmap pmp1(":/resources/user_image.png");
pmp1.scaled(ui->label_UserImage->size(), Qt::KeepAspectRatio);
ui->label_UserImage->setScaledContents(true);
ui->label_UserImage->setPixmap(pmp1);
ui->label_UserName->setText(u8"没有做完的梦最痛");
ui->label_UserName->setStyleSheet(qss);
ui->label_VipInfo->setText("");
QPixmap pmp2(":/resources/vipinfo.png");
pmp2.scaled(ui->label_VipInfo->size(), Qt::KeepAspectRatio);
ui->label_VipInfo->setScaledContents(true);
ui->label_VipInfo->setPixmap(pmp2);
}
UserInfoWidget::~UserInfoWidget()
{
delete ui;
}
以上就是Qt里实现绘制带三角形箭头的窗口的简单介绍。
都看到这里了,点个赞再走呗朋友~
加油吧,预祝大家变得更强!