Qt实现蚂蚁线

【Qt】蚂蚁线绘制实现_qt蚂蚁线-CSDN博客

(1) 头文件

cpp 复制代码
#ifndef ANTLINEWIDGET_H
#define ANTLINEWIDGET_H

#include <QWidget>
#include <QColor>
#include <QTimer>
#include <QPainterPath>

// 继承 QWidget 并启用 Qt 元对象系统
class AntLineWidget : public QWidget {
    Q_OBJECT

public:
    // 构造函数
    explicit AntLineWidget(QWidget *parent = nullptr);

    // Getter 函数
    QColor getLineColor() const;

public slots:
    // 槽函数声明 (用于接收信号)
    void setShape(int shapeType);
    void setLineWidth(int width);
    void setDashSize(int size);
    void setGapSize(int size);
    void setLineColor(const QColor &color);
    void setShowControlPoints(bool show);

protected:
    // 重绘事件
    void paintEvent(QPaintEvent *event) override;

private:
    // 成员变量
    QTimer *timer;
    int offset;
    int lineWidth;
    int dashSize;
    int gapSize;
    QColor lineColor;
    int shape;
    bool showControlPoints;
};

#endif // ANTLINEWIDGET_H

(2) 源文件

cpp 复制代码
#include "antlinewidget.h"
#include <QPainter>
#include <QVector>
#include <QtMath>
#include <QPointF>

AntLineWidget::AntLineWidget(QWidget *parent)
    : QWidget(parent),
    offset(0),
    lineWidth(3),
    dashSize(8),
    gapSize(8),
    lineColor(Qt::black),
    shape(0),
    showControlPoints(false)
{
    // 初始化定时器
    timer = new QTimer(this);
    connect(timer, &QTimer::timeout, [this]() {
        // 更新偏移量以实现动画
        offset = (offset + 1) % (dashSize + gapSize);
        update(); // 触发重绘
    });

    /*80ms 刷新一次*/
    timer->start(80);

    setMinimumSize(500, 400);
}

QColor AntLineWidget::getLineColor() const {
    return lineColor;
}

void AntLineWidget::setShape(int shapeType) {
    shape = shapeType;
    update();
}

void AntLineWidget::setLineWidth(int width) {
    lineWidth = width;
    update();
}

void AntLineWidget::setDashSize(int size) {
    dashSize = size;
    update();
}

void AntLineWidget::setGapSize(int size) {
    gapSize = size;
    update();
}

void AntLineWidget::setLineColor(const QColor &color) {
    lineColor = color;
    update();
}

void AntLineWidget::setShowControlPoints(bool show) {
    showControlPoints = show;
    update();
}

void AntLineWidget::paintEvent(QPaintEvent *) {
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing, true); // 开启抗锯齿

    QPainterPath path;
    int margin = 60;

    // 边界检查,防止窗口过小时计算出错
    if (width() <= 2 * margin || height() <= 2 * margin) {
        return;
    }

    // 根据形状类型绘制路径
    switch(shape) {
    case 0: // 圆角矩形
        path.addRoundedRect(margin, margin,
                            width() - 2*margin, height() - 2*margin,
                            20, 20);
        break;
    case 1: // 圆形
        path.addEllipse(margin, margin,
                        width() - 2*margin, height() - 2*margin);
        break;
    case 2: // 三角形
        path.moveTo(width()/2, margin);
        path.lineTo(width() - margin, height() - margin);
        path.lineTo(margin, height() - margin);
        path.closeSubpath();
        break;
    case 3: // 自定义贝塞尔曲线
        path.moveTo(width()/4, height()/4);
        path.cubicTo(width()/2, margin,
                     width() - margin, height()/3,
                     width()/2, height() - margin);
        path.cubicTo(margin, height() - margin,
                     width()/4, height()/2,
                     width()/4, height()/4);
        break;
    }

    // 设置画笔属性 (颜色、宽度、虚线样式)
    QPen pen(lineColor, lineWidth);
    QVector<qreal> dashPattern;
    dashPattern << dashSize << gapSize;
    pen.setDashPattern(dashPattern);
    pen.setDashOffset(offset); // 应用动态偏移
    painter.setPen(pen);

    // 绘制路径
    painter.drawPath(path);

    // 如果开启了控制点显示且是自定义形状,绘制控制点
    if (showControlPoints && shape == 3) {
        painter.setPen(Qt::red);
        painter.setBrush(Qt::red);

        // 起点
        painter.drawEllipse(QPointF(width()/4, height()/4), 5, 5);
        // 控制点 1
        painter.drawEllipse(QPointF(width()/2, margin), 5, 5);
        // 控制点 2
        painter.drawEllipse(QPointF(width() - margin, height()/3), 5, 5);
        // 中间点/控制点 3
        painter.drawEllipse(QPointF(width()/2, height() - margin), 5, 5);
        // 控制点 4
        painter.drawEllipse(QPointF(margin, height() - margin), 5, 5);
        // 控制点 5
        painter.drawEllipse(QPointF(width()/4, height()/2), 5, 5);
    }
}

(3) 应用示例

cpp 复制代码
#include "widget.h"
#include <QtWidgets>
#include "antlinewidget.h"

CWidget::CWidget(QWidget *parent)
    : QWidget(parent)
{
    this->setWindowTitle("Qt 蚂蚁线效果演示 (分离版)");
    this->resize(800, 600);

    QVBoxLayout *mainLayout = new QVBoxLayout(this);

    // 实例化自定义控件
    AntLineWidget *antWidget = new AntLineWidget;
    mainLayout->addWidget(antWidget, 1);

    // --- 控制面板布局 ---
    QHBoxLayout *controlsLayout = new QHBoxLayout;

    // 1. 形状选择
    QGroupBox *shapeGroup = new QGroupBox("形状选择");
    QVBoxLayout *shapeLayout = new QVBoxLayout;
    QRadioButton *rectBtn = new QRadioButton("圆角矩形");
    QRadioButton *circleBtn = new QRadioButton("圆形");
    QRadioButton *triangleBtn = new QRadioButton("三角形");
    QRadioButton *customBtn = new QRadioButton("自定义路径");

    rectBtn->setChecked(true);
    shapeLayout->addWidget(rectBtn);
    shapeLayout->addWidget(circleBtn);
    shapeLayout->addWidget(triangleBtn);
    shapeLayout->addWidget(customBtn);
    shapeGroup->setLayout(shapeLayout);
    controlsLayout->addWidget(shapeGroup);

    QButtonGroup *shapeGroupBtns = new QButtonGroup(this);
    shapeGroupBtns->addButton(rectBtn, 0);
    shapeGroupBtns->addButton(circleBtn, 1);
    shapeGroupBtns->addButton(triangleBtn, 2);
    shapeGroupBtns->addButton(customBtn, 3);

    QObject::connect(shapeGroupBtns, &QButtonGroup::idToggled,
                     [antWidget](int id, bool checked) {
                         if (checked) antWidget->setShape(id);
                     });

    // 2. 线宽控制
    QGroupBox *widthGroup = new QGroupBox("线宽");
    QSlider *widthSlider = new QSlider(Qt::Horizontal);
    widthSlider->setRange(1, 10);
    widthSlider->setValue(3);
    QVBoxLayout *widthLayout = new QVBoxLayout;
    widthLayout->addWidget(widthSlider);
    widthGroup->setLayout(widthLayout);
    controlsLayout->addWidget(widthGroup);

    // 3. 虚线设置
    QGroupBox *dashGroup = new QGroupBox("虚线设置");
    QFormLayout *dashLayout = new QFormLayout;
    QSlider *dashSlider = new QSlider(Qt::Horizontal);
    dashSlider->setRange(3, 20);
    dashSlider->setValue(8);
    QSlider *gapSlider = new QSlider(Qt::Horizontal);
    gapSlider->setRange(3, 20);
    gapSlider->setValue(8);

    dashLayout->addRow("实线长度:", dashSlider);
    dashLayout->addRow("空白长度:", gapSlider);
    dashGroup->setLayout(dashLayout);
    controlsLayout->addWidget(dashGroup);

    // 4. 选项
    QGroupBox *optionsGroup = new QGroupBox("选项");
    QVBoxLayout *optionsLayout = new QVBoxLayout;
    QPushButton *colorBtn = new QPushButton("选择颜色");
    QCheckBox *controlPoints = new QCheckBox("显示控制点");

    optionsLayout->addWidget(colorBtn);
    optionsLayout->addWidget(controlPoints);
    optionsGroup->setLayout(optionsLayout);
    controlsLayout->addWidget(optionsGroup);

    mainLayout->addLayout(controlsLayout);

    // --- 信号连接 ---
    QObject::connect(widthSlider, &QSlider::valueChanged, antWidget, &AntLineWidget::setLineWidth);
    QObject::connect(dashSlider, &QSlider::valueChanged, antWidget, &AntLineWidget::setDashSize);
    QObject::connect(gapSlider, &QSlider::valueChanged, antWidget, &AntLineWidget::setGapSize);

    QObject::connect(colorBtn, &QPushButton::clicked, [antWidget, colorBtn]() {
        QColor currentColor = antWidget->getLineColor();
        QColor color = QColorDialog::getColor(currentColor, colorBtn, "选择线条颜色");
        if (color.isValid()) {
            antWidget->setLineColor(color);
        }
    });

    QObject::connect(controlPoints, &QCheckBox::toggled, antWidget, &AntLineWidget::setShowControlPoints);
}

CWidget::~CWidget() {

}
相关推荐
布局呆星2 小时前
Python 文件操作教程
开发语言·python
Elnaij2 小时前
从C++开始的编程生活(23)——哈希表
开发语言·c++
英英_2 小时前
优化 MATLAB MapReduce 程序性能:从基础调优到进阶提速
开发语言·matlab·mapreduce
LSL666_2 小时前
BaseMapper——新增和删除
java·开发语言·mybatis·mybatisplus
xiangpanf2 小时前
PHP vs C语言:30字解析两大编程语言差异
c语言·开发语言·php
wdfk_prog2 小时前
MAX14830 可移植 C 驱动实现分析:一个适合多串口扩展场景的开源基础版本
c语言·开发语言·开源
Ivy_belief2 小时前
Qt网络编程实战:从零掌握 QUdpSocket 及 UDP 通信
网络·qt·udp
Elnaij2 小时前
从C++开始的编程生活(22)——红黑树
开发语言·c++
.select.2 小时前
STL下常见容器底层数据结构
开发语言·c++