qt中实现绘制图形与截图

引言

实现可以选择线型,线宽,颜色,是否填充图形来绘制各种常见的图形,同时可以选择矩形区域来实现截图。

效果

在这里插入图片描述
绘图的效果如上,截图的效果:
在这里插入图片描述

实现

项目使用的qt5.13.2,编译器为MSVC2017_64bit,该项目是基于基类QWidget创建的应用程序,创建时带有ui文件。下面是整个项目的代码。
main.cpp

#include "widget.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QPen>
#include <QStack>
#include <QPixmap>
#include "screenshot.h"

/********************************************
        ======功能描述:=======
        1.绘制曲线,
        2.绘制直线,
        3.绘制矩形,
        4.绘制椭圆,
        5.绘制三角形,
        6.绘制平行四边形,
        7.绘制菱形,
        8.绘制梯形,
        9.可以选择绘制图形的颜色,
        10.在选择颜色后可以设置是否填充,
        11.可以选择线型,
        12.可以选择线宽,
        13.撤销,
        14.剪裁保存。
        不足:
        曲线含有明显的折点,不平滑。
        心得:
        1.实时画直线只需要记住起点,然后更新终点,来画线;
        2.保存每条线的颜色时只保存一次,不能在绘制的时候保存,必须在鼠标释放时保存,曲线除外,
        曲线从鼠标点击后一直开始绘制,保存曲线绘制的颜色,必须在鼠标点击后保存;
        3.图形的填充也需在每个图形绘制的时候保存该图形是否填充,直线和曲线不需要设置填充;
        4.注意不能再改类中直接创建截图的蒙层,也就是说截图功能得单独实现,之所以这么做的原因:
            创建的蒙层存在与应用程序的窗口,而不是整个桌面,与此同时图片会嵌入到应用程序的窗口中,
            不是所希望的,主要由于绘图事件是在这个应用程序的窗口中进行绘制。
********************************************/

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

struct stuLine//直线
{
    int     startX;//按下点的x
    int     startY;//按下点的y
    int     endX;//终点的x(移动过程中的点,释放时的点)
    int     endY;//终点的y(移动过程中的点,释放时的点)
};

struct stuRectangle//矩形
{
    int     startX;//按下点的x
    int     startY;//按下点的y
    int     width;//矩形宽
    int     height;//矩形高
};

struct stuEllipse//圆或者椭圆
{
    int     startX;//按下点的x
    int     startY;//按下点的y
    int     width;//矩形宽
    int     height;//矩形高
};

struct stuTriangle//三角形(使用路径绘制)
{
    int     startX;//按下点的x
    int     startY;//按下点的y
    int     endX;//终点的x(移动过程中的点,释放时的点)
    int     endY;//终点的y(移动过程中的点,释放时的点)
};

struct stuParallelogram//平行四边形(使用路径绘制)
{
    int     startX;//按下点的x
    int     startY;//按下点的y
    int     endX;//终点的x(移动过程中的点,释放时的点)
    int     endY;//终点的y(移动过程中的点,释放时的点)
};

struct stuTrapezoid//梯形(路径绘制)
{
    int     startX;//按下点的x
    int     startY;//按下点的y
    int     endX;//终点的x(移动过程中的点,释放时的点)
    int     endY;//终点的y(移动过程中的点,释放时的点)
};

struct stuDiamond//菱形(路径绘制)
{
    int     startX;//按下点的x
    int     startY;//按下点的y
    int     endX;//终点的x(移动过程中的点,释放时的点)
    int     endY;//终点的y(移动过程中的点,释放时的点)
};

class Widget : public QWidget
{
    Q_OBJECT

    enum graphicType{//其实在这种情况下,只要给第一个赋值就行
        noShape = 0,
        line = 1,
        curve = 2,
        rectangle = 3,
        ellipse = 4,
        triangle = 5,//三角形
        Trapezoid = 6,//梯形
        Parallelogram = 7,//平行四边形
        diamond = 8//菱形
    };
public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
private:
    void initLineType();//初始化线型下拉列表
    void initPenBrushLine();//初始化画笔,画刷,以及线型等
    void setBrushPenColor();//设置画笔和画刷颜色(这里画笔和画刷相同颜色)
    bool isContainInRect(QPoint pos);//包含的点是否在矩形内

    void clearLastPaintLine();//清屏之后,给最后一个绘制的直线赋空
    void clearLastPaintRectangle();//清屏之后,给最后一个绘制的矩形赋空
    void clearLastPaintEllipse();//清屏之后,将最后一个绘制的椭圆赋空
    void clearLastPaintDiamond();//清屏之后,给最后一个绘制的菱形赋空
    void clearLastPaintParallelogram();//清屏之后,给最后一个绘制的平行四边形赋空
    void clearLastPaintTrapezoid();//清屏之后,给最后一个绘制的梯形赋空
    void clearLastPaintTriangle();//清屏之后,给最后一个绘制的三角形赋空
protected:
    void mousePressEvent(QMouseEvent *event);
    void mouseMoveEvent(QMouseEvent *event);
    void mouseReleaseEvent(QMouseEvent *event);
    void paintEvent(QPaintEvent *event);//绘制线
//    void keyPressEvent(QKeyEvent *event);//按键事件(按键切换的时候与线宽设置相冲突,spinBox接收了事件)
private slots:
    void on_clearBtn_clicked();//清除画布上绘制的内容
    void on_colorBtn_clicked();//选择颜色
    void on_lineTypeCombox_activated(const QString &arg1);//选择的线型
    void on_checkBox_clicked(bool checked);//是否填充图形
    void on_spinBox_valueChanged(int arg1);//设置的线宽

    void on_lineBtn_clicked();//绘制直线
    void on_curveBtn_clicked();//绘制曲线
    void on_rectangleBtn_clicked();//绘制矩形
    void on_ellipseBtn_clicked();//绘制椭圆
    void on_triangleBtn_clicked();//绘制三角形
    void on_parallelogramBtn_clicked();//绘制平行四边形
    void on_TrapezoidBtn_clicked();//绘制梯形
    void on_diamondBtn_clicked();//绘制菱形
    void on_undoBtn_clicked();//撤销之前绘制的图形
    void on_screenshotSaveBtn_clicked();//截图保存

private:
    Ui::Widget *ui;
    graphicType                 m_type;//当前绘制的图形所属图形的类型
    QPen                        m_pen;//画笔
    QBrush                      m_brush;//填充用的画刷
    QColor                      m_color;//绘制图形的颜色
    bool                        m_isFill;//是否填充图形true-是
    bool                        m_isClear;//是否清屏(为了清屏功能正常使用)
    bool                        m_isPress;//是否鼠标左键点击(为了解决点击线型下拉列表的时候,不让进入鼠标移动事件,从而引起绘图)
    QStack<graphicType>         m_typeStack;//按序保存绘制图形的类型

    stuLine                     m_line;//暂存每段直线中的点
    QVector<stuLine>            m_lineVec;//保存未清屏前所有直线的点
    QVector<QPen>               m_penLineVec;//保存所有的直线的画笔

    stuRectangle                m_rectangle;//暂存矩形中的点
    QVector<stuRectangle>       m_rectangleVec;//保存未清屏前所有的矩形
    QVector<QPen>               m_rectanglePen;//保存绘制每一个矩形的画笔
    QVector<QBrush>             m_rectangleBrush;//保存之前绘制的图形的画刷

    stuEllipse                  m_ellipse;//暂存椭圆中的点
    QVector<stuEllipse>         m_ellipseVec;//保存未清屏前所有绘制的椭圆
    QVector<QPen>               m_ellipsePen;//保存绘制每一个椭圆的画笔
    QVector<QBrush>             m_ellipseBrush;//保存每一个椭圆的填充色

    stuDiamond                  m_diamond;//暂存菱形中的点
    QVector<stuDiamond>         m_diamondVec;//保存未清屏之前所有绘制菱形的点
    QVector<QPen>               m_diamondPen;//保存绘制每一个菱形的画笔
    QVector<QBrush>             m_diamondBrush;//保存每个菱形的画刷

    stuParallelogram            m_parallelogram;//暂存平行四边形中的点
    QVector<stuParallelogram>   m_parallelogramVec;//保存未清屏之前绘制平行四边形的点
    QVector<QPen>               m_parallelogramPen;//保存每次绘制平行四边形的画笔
    QVector<QBrush>             m_parallelogramBrush;//保存每个平行四边形的画刷

    stuTrapezoid                m_trapezoid;//暂存梯形中的点
    QVector<stuTrapezoid>       m_trapezoidVec;//暂存为清屏之前的点
    QVector<QPen>               m_trapezoidPen;//保存每次绘制梯形的画笔
    QVector<QBrush>             m_trapezoidBrush;//保存每个梯形的画刷

    stuTriangle                 m_triangle;//暂存三角形中的点
    QVector<stuTriangle>        m_triangleVec;//保存未清屏之前绘制三角形
    QVector<QPen>               m_trianglePen;//保存每次绘制三角形的画笔
    QVector<QBrush>             m_triangleBrush;//保存每个三角形的画刷

    QVector<QPen>               m_curvePen;//绘制曲线的画笔
    QVector<QVector<QPoint>>    m_lines;//保存未清屏之前所有曲线的起始点和终止点
};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include <QMouseEvent>
#include <QPainter>
#include <QColorDialog>
#include <QVector>
#include <QTextDocumentFragment>
#include <QScreen>
#include <QDesktopWidget>
#include <QDebug>

const QString strSolidLine = QStringLiteral("实线");
const QString strDashLine = QStringLiteral("虚线");
const QString strDotLine = QStringLiteral("点画线");
const QString strDashDotLine = QStringLiteral("点线画线");
const QString strDashDotDotLine = QStringLiteral("线点点画线");
const QString strCustomDashLine = QStringLiteral("自定义虚线");

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    resize(1100,1000);
    initLineType();
    initPenBrushLine();
}

Widget::~Widget()
{
    delete ui;
}

void Widget::initLineType()
{
    QStringList lineTye;
    lineTye<<strSolidLine<<strDashLine<<strDotLine<<strDashDotLine<<strDashDotDotLine
    <<strCustomDashLine;
    ui->lineTypeCombox->insertItems(0,lineTye);
}

void Widget::initPenBrushLine()
{
    m_color = QColor(Qt::darkRed);
    m_pen.setWidth(5);
    m_pen.setStyle(Qt::SolidLine);
    m_pen.setCapStyle(Qt::RoundCap);
    m_pen.setJoinStyle(Qt::RoundJoin);
    m_pen.setColor(m_color);

    m_brush.setColor(Qt::transparent);
    m_brush.setStyle(Qt::Dense2Pattern);
    m_isFill = false;
    m_type = Widget::curve;
    m_isPress = false;
}

void Widget::setBrushPenColor()
{
    m_pen.setColor(m_color);
     if (m_isFill) {
        m_brush.setColor(m_color);
     }else {
        m_brush.setColor(Qt::transparent);
     }
}

bool Widget::isContainInRect(QPoint pos)
{
    QRect rectRangle = QRect(6,70,rect().width()-12,rect().height()-70 - 12);
    if (rectRangle.contains(pos)) {
        return true;
    }
    return false;
}

void Widget::clearLastPaintLine()
{
    m_line.startX = 0;
    m_line.startY = 0;
    m_line.endX = 0;
    m_line.endY = 0;
}

void Widget::clearLastPaintRectangle()
{
    m_rectangle.startX = 0;
    m_rectangle.startY = 0;
    m_rectangle.width = 0;
    m_rectangle.height = 0;
}

void Widget::clearLastPaintEllipse()
{
    m_ellipse.startX = 0;
    m_ellipse.startY = 0;
    m_ellipse.width = 0;
    m_ellipse.height = 0;
}

void Widget::clearLastPaintDiamond()
{
    m_diamond.startX = 0;
    m_diamond.startY = 0;
    m_diamond.endX = 0;
    m_diamond.endY = 0;
}

void Widget::clearLastPaintParallelogram()
{
    m_parallelogram.startX = 0;
    m_parallelogram.startY = 0;
    m_parallelogram.endX = 0;
    m_parallelogram.endY = 0;
}

void Widget::clearLastPaintTrapezoid()
{
    m_trapezoid.startX = 0;
    m_trapezoid.startY = 0;
    m_trapezoid.endX = 0;
    m_trapezoid.endY = 0;
}

void Widget::clearLastPaintTriangle()
{
    m_triangle.startX = 0;
    m_triangle.startY = 0;
    m_triangle.endX = 0;
    m_triangle.endY = 0;
}

void Widget::mousePressEvent(QMouseEvent *event)
{
    bool isContain = isContainInRect(event->pos());
    if (event->button() == Qt::LeftButton && isContain) {
        m_isPress = true;
        QPoint startPos = event->pos();
        if (m_type == 1) {
            m_line.startX = startPos.x();
            m_line.startY = startPos.y();
        }else if (m_type == 2) {
            QVector<QPoint> lineVec;
            lineVec.append(startPos);
            m_lines.append(lineVec);
            m_curvePen.append(m_pen);
            update();
        }else if (m_type == 3) {
            m_rectangle.startX = startPos.x();
            m_rectangle.startY = startPos.y();
        }else if (m_type == 4) {
            m_ellipse.startX = startPos.x();
            m_ellipse.startY = startPos.y();
        }else if (m_type == 5) {
            m_triangle.startX = startPos.x();
            m_triangle.startY = startPos.y();
        }else if (m_type == 6) {
            m_trapezoid.startX = startPos.x();
            m_trapezoid.startY = startPos.y();
        }else if (m_type == 7) {
            m_parallelogram.startX = startPos.x();
            m_parallelogram.startY = startPos.y();
        }else if (m_type == 8) {
            m_diamond.startX = startPos.x();
            m_diamond.startY = startPos.y();
        }
    }
    QWidget::mousePressEvent(event);
}

void Widget::mouseMoveEvent(QMouseEvent *event)
{
    bool isContain = isContainInRect(event->pos());
    if (event->buttons() == Qt::LeftButton && m_isPress && isContain) {
        QPoint curPos = event->pos();
        if (m_type == 1) {//直线
            m_line.endX = curPos.x();
            m_line.endY = curPos.y();
            update();
        }else if (m_type == 2) {//曲线
            if (!m_lines.size()) {
                QVector<QPoint> lineVec;
                m_lines.append(lineVec);
            }
            QVector<QPoint> &lineVec = m_lines.last();
            lineVec.append(curPos);
            update();
        }else if (m_type == 3) {//矩形
            m_rectangle.width = curPos.x() - m_rectangle.startX;
            m_rectangle.height = curPos.y() - m_rectangle.startY;

            update();
        }else if (m_type == 4) {//椭圆
            m_ellipse.width = curPos.x() - m_ellipse.startX;
            m_ellipse.height = curPos.y() - m_ellipse.startY;

            update();
        }else if (m_type == 5) {//三角形
            m_triangle.endX = curPos.x();
            m_triangle.endY = curPos.y();

            update();
        }else if (m_type == 6) {//梯形
            m_trapezoid.endX = curPos.x();
            m_trapezoid.endY = curPos.y();

            update();
        }else if (m_type == 7) {//平行四边形
            m_parallelogram.endX = curPos.x();
            m_parallelogram.endY = curPos.y();

            update();
        }else if (m_type == 8) {
            m_diamond.endX = curPos.x();
            m_diamond.endY = curPos.y();

            update();
        }
    }
    QWidget::mouseMoveEvent(event);
}

void Widget::mouseReleaseEvent(QMouseEvent *event)
{
    bool isContain = isContainInRect(event->pos());
    if (event->button() == Qt::LeftButton && isContain) {
        QPoint endPos = event->pos();
        if (m_type == 1) {
            m_line.endX = endPos.x();
            m_line.endY = endPos.y();

            //此时只保存了每条直线的起点和终点
            m_lineVec.append(m_line);
            m_penLineVec.append(m_pen);//每条线对应的画笔储存
            m_typeStack.push(line);

            update();
        }else if (m_type == 2) {
            QVector<QPoint> &lineVec = m_lines.last();
            lineVec.append(endPos);
            m_typeStack.push(curve);

            update();
        }else if (m_type == 3) {
            m_rectangle.width = endPos.x() - m_rectangle.startX;
            m_rectangle.height = endPos.y() - m_rectangle.startY;

            m_rectangleVec.append(m_rectangle);
            m_rectanglePen.append(m_pen);
            m_rectangleBrush.append(m_brush);
            m_typeStack.push(rectangle);
            update();
        }else if (m_type == 4) {
            m_ellipse.width = endPos.x() - m_ellipse.startX;
            m_ellipse.height = endPos.y() - m_ellipse.startY;
            m_ellipseVec.append(m_ellipse);
            m_ellipsePen.append(m_pen);
            m_ellipseBrush.append(m_brush);
            m_typeStack.push(ellipse);

            update();
        }else if (m_type == 5) {
            m_triangle.endX = endPos.x();
            m_triangle.endY = endPos.y();
            m_triangleVec.append(m_triangle);
            m_trianglePen.append(m_pen);
            m_triangleBrush.append(m_brush);
            m_typeStack.push(triangle);

            update();
        }else if (m_type == 6) {
            m_trapezoid.endX = endPos.x();
            m_trapezoid.endY = endPos.y();
            m_trapezoidVec.append(m_trapezoid);
            m_trapezoidPen.append(m_pen);
            m_trapezoidBrush.append(m_brush);
            m_typeStack.push(Trapezoid);

            update();
        }else if (m_type == 7) {
            m_parallelogram.endX = endPos.x();
            m_parallelogram.endY = endPos.y();
            m_parallelogramVec.append(m_parallelogram);
            m_parallelogramPen.append(m_pen);
            m_parallelogramBrush.append(m_brush);
            m_typeStack.push(Parallelogram);

            update();
        }else if (m_type == 8) {
            m_diamond.endX = endPos.x();
            m_diamond.endY = endPos.y();
            m_diamondVec.append(m_diamond);
            m_diamondPen.append(m_pen);
            m_diamondBrush.append(m_brush);
            m_typeStack.push(diamond);

            update();
        }
        m_isPress = false;
    }
    QWidget::mouseReleaseEvent(event);
}

void Widget::paintEvent(QPaintEvent *event)
{
#if 0
    QPainter painter(this);
    QPen pen;
    pen.setWidth(4);
    pen.setColor(Qt::red);
    pen.setCapStyle(Qt::RoundCap);
    pen.setJoinStyle(Qt::RoundJoin);
    pen.setStyle(Qt::SolidLine);
    painter.setPen(pen);
    painter.setRenderHint(QPainter::Antialiasing, true);

    for (int i = 0; i < m_lines.size(); ++i) {
        QVector<QPoint> &lines = m_lines[i];
        for (int j =0; j < lines.size() - 1; ++j) {
            painter.drawLine(lines[j],lines[j+1]);
        }
    }
#endif
    QPainter painter(this);
    painter.setPen(m_pen);
    painter.setBrush(m_brush);
    painter.setRenderHint(QPainter::Antialiasing, true);

    if (!m_isClear) {
        if (m_type == 1) {//绘制单个实时直线(画笔不能放在这里保存,因为鼠标开始移动的时候,都会进入这里,对于一个颜色的画笔就会追加很多遍,而实际只需要一次)
            painter.drawLine(QPoint(m_line.startX,m_line.startY),QPoint(m_line.endX,m_line.endY));
        }else if (m_type == 2) {//绘制所有的曲线
            for (int i = 0; i < m_lines.size(); ++i) {
                QVector<QPoint> &lines = m_lines[i];
                for (int j =0; j < lines.size() - 1; ++j) {
                    painter.drawLine(lines[j],lines[j+1]);
                }
            }
        }else if (m_type == 3) {//绘制单个实时矩形
            painter.drawRect(m_rectangle.startX,m_rectangle.startY,m_rectangle.width,m_rectangle.height);
        }else if (m_type == 4) {//绘制单个实时椭圆
            painter.drawEllipse(m_ellipse.startX,m_ellipse.startY,m_ellipse.width,m_ellipse.height);
        }else if (m_type == 5) {//绘制单个实时三角形(通过路径绘制和直线绘制)
            //通过直线绘制三角形(目前没有填充,因为本质上是直线)
            #if 0
            painter.drawLine(m_triangle.startX,m_triangle.startY,m_triangle.endX,m_triangle.endY);
            if (m_triangle.endX > m_triangle.startX) {
               painter.drawLine(m_triangle.endX,m_triangle.endY,m_triangle.endX-2*(m_triangle.endX - m_triangle.startX),m_triangle.endY);
               painter.drawLine(m_triangle.endX-2*(m_triangle.endX - m_triangle.startX),m_triangle.endY,m_triangle.startX,m_triangle.startY);
            }else {//abs(m_triangle.endX - abs(m_triangle.endY -m_triangle.startY))
               painter.drawLine(m_triangle.endX,m_triangle.endY,m_triangle.endX + 2*(m_triangle.startX - m_triangle.endX),m_triangle.endY);
               painter.drawLine(m_triangle.endX + 2*(m_triangle.startX - m_triangle.endX),m_triangle.endY,m_triangle.startX,m_triangle.startY);
            }
            #endif
            if (m_triangle.endX > m_triangle.startX) {//通过路径绘制三角形是一个封闭的三角形可以填充
                QPainterPath path;
                path.moveTo(m_triangle.startX,m_triangle.startY);
                path.lineTo(m_triangle.startX,m_triangle.startY);
                path.lineTo(m_triangle.endX,m_triangle.endY);
                path.lineTo(m_triangle.endX - 2*(m_triangle.endX - m_triangle.startX),m_triangle.endY);
                path.lineTo(m_triangle.startX,m_triangle.startY);
                painter.drawPath(path);//可以绘制边框线
//                painter.fillPath(path,m_brush);//使用该函数绘制的路径不能边框线
            }else {
                QPainterPath path;
                path.moveTo(m_triangle.startX,m_triangle.startY);
                path.lineTo(m_triangle.startX,m_triangle.startY);
                path.lineTo(m_triangle.endX,m_triangle.endY);
                path.lineTo(m_triangle.endX + 2*(m_triangle.startX - m_triangle.endX),m_triangle.endY);
                path.lineTo(m_triangle.startX,m_triangle.startY);
                painter.drawPath(path);
//                painter.fillPath(path,m_brush);
            }
        }else if (m_type == 6) {
            if (m_trapezoid.startX < m_trapezoid.endX) {
                #if 1
                QPainterPath path;
                path.moveTo(m_trapezoid.startX,m_trapezoid.startY);
                path.lineTo(m_trapezoid.startX,m_trapezoid.startY);
                path.lineTo(m_trapezoid.startX-40,m_trapezoid.endY);
                path.lineTo(m_trapezoid.endX,m_trapezoid.endY);
                path.lineTo(m_trapezoid.endX-40,m_trapezoid.startY);
                path.lineTo(m_trapezoid.startX,m_trapezoid.startY);
                painter.drawPath(path);
//                painter.fillPath(path,m_brush);
                #endif
                #if 0
                QPointF points[4] = {
                    QPointF(m_trapezoid.startX,m_trapezoid.startY),
                    QPointF(qAbs(m_trapezoid.startX-50),m_trapezoid.endY),
                    QPointF(m_trapezoid.endX,m_trapezoid.endY),
                    QPointF(qAbs(m_trapezoid.endX-50),m_trapezoid.startY)
                };
                painter.drawPolygon(points,4);//绘制多边形
                #endif
            }else {
            #if 1
                QPainterPath path;
                path.moveTo(m_trapezoid.startX,m_trapezoid.startY);
                path.lineTo(m_trapezoid.startX,m_trapezoid.startY);
                path.lineTo(m_trapezoid.endX+40,m_trapezoid.startY);
                path.lineTo(m_trapezoid.endX,m_trapezoid.endY);
                path.lineTo(m_trapezoid.startX+40,m_trapezoid.endY);
                path.lineTo(m_trapezoid.startX,m_trapezoid.startY);
                painter.drawPath(path);
//                painter.fillPath(path,m_brush);
            #endif
            }
        }else if (m_type == 7) {
            QPainterPath path;
            path.moveTo(m_parallelogram.startX,m_parallelogram.startY);
            path.lineTo(m_parallelogram.startX,m_parallelogram.startY);
            path.lineTo(m_parallelogram.startX+30,m_parallelogram.endY);
            path.lineTo(m_parallelogram.endX,m_parallelogram.endY);
            path.lineTo(m_parallelogram.endX-30,m_parallelogram.startY);
            path.lineTo(m_parallelogram.startX,m_parallelogram.startY);
            painter.drawPath(path);
//            painter.fillPath(path,m_brush);
        }else if (m_type == 8) {
            if (m_diamond.startY < m_diamond.endY && abs(m_diamond.startX - m_diamond.endX)<30) {
                QPainterPath path;
                path.moveTo(m_diamond.startX,m_diamond.startY);
                path.lineTo(m_diamond.startX,m_diamond.startY);
                path.lineTo(m_diamond.startX+40,m_diamond.startY+(m_diamond.endY-m_diamond.startY)/2);
                path.lineTo(m_diamond.startX,m_diamond.endY);
                path.lineTo(m_diamond.startX-40,m_diamond.startY+(m_diamond.endY-m_diamond.startY)/2);
                path.lineTo(m_diamond.startX,m_diamond.startY);
                painter.drawPath(path);
//                painter.fillPath(path,m_brush);
            }else if (m_diamond.startX < m_diamond.endX && abs(m_diamond.endY-m_diamond.startY)<30) {
                QPainterPath path;
                path.moveTo(m_diamond.startX,m_diamond.startY);
                path.lineTo(m_diamond.startX,m_diamond.startY);
                path.lineTo(m_diamond.startX+abs(m_diamond.endX-m_diamond.startX)/2,m_diamond.startY-40);
                path.lineTo(m_diamond.endX,m_diamond.startY);
                path.lineTo(m_diamond.startX+abs(m_diamond.endX-m_diamond.startX)/2,m_diamond.startY+40);
                path.lineTo(m_diamond.startX,m_diamond.startY);
                painter.drawPath(path);
//                painter.fillPath(path,m_brush);
            }else if (m_diamond.startY > m_diamond.endY && abs(m_diamond.startX - m_diamond.endX)<30) {
                QPainterPath path;
                path.moveTo(m_diamond.startX,m_diamond.startY);
                path.lineTo(m_diamond.startX,m_diamond.startY);
                path.lineTo(m_diamond.startX-40,m_diamond.startY-(m_diamond.startY-m_diamond.endY)/2);
                path.lineTo(m_diamond.startX,m_diamond.endY);
                path.lineTo(m_diamond.startX+40,m_diamond.startY-(m_diamond.startY-m_diamond.endY)/2);
                path.lineTo(m_diamond.startX,m_diamond.startY);
                painter.drawPath(path);
//                painter.fillPath(path,m_brush);
            }else if (m_diamond.startX > m_diamond.endX && abs(m_diamond.endY-m_diamond.startY)<30) {
                QPainterPath path;
                path.moveTo(m_diamond.startX,m_diamond.startY);
                path.lineTo(m_diamond.startX,m_diamond.startY);
                path.lineTo(m_diamond.startX-(m_diamond.startX-m_diamond.endX)/2,m_diamond.startY+40);
                path.lineTo(m_diamond.endX,m_diamond.startY);
                path.lineTo(m_diamond.startX-(m_diamond.startX-m_diamond.endX)/2,m_diamond.startY-40);
                path.lineTo(m_diamond.startX,m_diamond.startY);
                painter.drawPath(path);
//                painter.fillPath(path,m_brush);
            }
        }

        //在这之前只能只能绘制单个直线,下面将之前保存的直线绘制
        for (int i = 0; i < m_lineVec.size(); ++i) {//直线
            QPen pen = m_penLineVec[i];//重新创建变量并保存在pen中,之前使用m_pen导致功能出错
            painter.setPen(pen);
            painter.drawLine(m_lineVec[i].startX,m_lineVec[i].startY,m_lineVec[i].endX,m_lineVec[i].endY);
        }

        //将之前绘制的曲线在切换不同的图形绘制的时候再绘一遍
       for (int i = 0; i < m_lines.size(); ++i) {//曲线
            QPen pen = m_curvePen[i];
            painter.setPen(pen);
            QVector<QPoint> &lines = m_lines[i];
            for (int j =0; j < lines.size() - 1; ++j) {
                painter.drawLine(lines[j],lines[j+1]);
            }
        }

        //将之前绘制的矩形重新绘制上(感觉刷新页面的时候都需要重新绘制)
       for (int i = 0; i < m_rectangleVec.size(); ++i) {//矩形
            QPen pen = m_rectanglePen.at(i);
            QBrush brush = m_rectangleBrush[i];
            painter.setPen(pen);
            painter.setBrush(brush);
            painter.drawRect(m_rectangleVec[i].startX,m_rectangleVec[i].startY,m_rectangleVec[i].width,m_rectangleVec[i].height);
        }

        //将之前绘制的椭圆重新绘制(没有这段代码,就会出现洗一次绘制的时候将之前绘制的椭圆清除)
        for (int i = 0; i < m_ellipseVec.size(); ++i) {
            QPen pen = m_ellipsePen.at(i);
            QBrush brush = m_ellipseBrush.at(i);
            painter.setPen(pen);
            painter.setBrush(brush);
            painter.drawEllipse(m_ellipseVec[i].startX,m_ellipseVec[i].startY,m_ellipseVec[i].width,m_ellipseVec[i].height);
        }

        //将之前绘制的三角形重新绘制(没有这段代码,只能绘制单个三角形)
        for (int i = 0;i < m_triangleVec.size(); ++i) {
            QPen pen = m_trianglePen[i];
            QBrush brush = m_triangleBrush[i];
            painter.setPen(pen);
            painter.setBrush(brush);
            stuTriangle tempTriangle = m_triangleVec[i];
            if (tempTriangle.endX > tempTriangle.startX) {//通过路径绘制三角形是一个封闭的三角形可以填充
                QPainterPath path;
                path.moveTo(tempTriangle.startX,tempTriangle.startY);
                path.lineTo(tempTriangle.startX,tempTriangle.startY);
                path.lineTo(tempTriangle.endX,tempTriangle.endY);
                path.lineTo(tempTriangle.endX - 2*(tempTriangle.endX - tempTriangle.startX),tempTriangle.endY);
                path.lineTo(tempTriangle.startX,tempTriangle.startY);
                painter.drawPath(path);
//                painter.fillPath(path,m_brush);
            }else {
                QPainterPath path;
                path.moveTo(tempTriangle.startX,tempTriangle.startY);
                path.lineTo(tempTriangle.startX,tempTriangle.startY);
                path.lineTo(tempTriangle.endX,tempTriangle.endY);
                path.lineTo(tempTriangle.endX + 2*(tempTriangle.startX - tempTriangle.endX),tempTriangle.endY);
                path.lineTo(tempTriangle.startX,tempTriangle.startY);
                painter.drawPath(path);
//                painter.fillPath(path,m_brush);
            }
        }

        //将之前所有绘制的梯形重新绘制,(没有这段代码,就只绘制当前的梯形)
        for (int i = 0; i < m_trapezoidVec.size(); ++i) {
            QPen pen = m_trapezoidPen[i];
            QBrush brush = m_trapezoidBrush[i];
            painter.setPen(pen);
            painter.setBrush(brush);
            stuTrapezoid trapezoid = m_trapezoidVec[i];
            if (trapezoid.startX < trapezoid.endX) {
                QPainterPath path;
                path.moveTo(trapezoid.startX,trapezoid.startY);
                path.lineTo(trapezoid.startX,trapezoid.startY);
                path.lineTo(trapezoid.startX-40,trapezoid.endY);
                path.lineTo(trapezoid.endX,trapezoid.endY);
                path.lineTo(trapezoid.endX-40,trapezoid.startY);
                path.lineTo(trapezoid.startX,trapezoid.startY);
                painter.drawPath(path);
//                painter.fillPath(path,m_brush);
            }else {
                QPainterPath path;
                path.moveTo(trapezoid.startX,trapezoid.startY);
                path.lineTo(trapezoid.startX,trapezoid.startY);
                path.lineTo(trapezoid.endX+40,trapezoid.startY);
                path.lineTo(trapezoid.endX,trapezoid.endY);
                path.lineTo(trapezoid.startX+40,trapezoid.endY);
                path.lineTo(trapezoid.startX,trapezoid.startY);
                painter.drawPath(path);
//                painter.fillPath(path,m_brush);
            }
        }

        //绘制之前绘制的平行四边形
        for (int i = 0; i < m_parallelogramVec.size(); ++i) {
            QPen pen = m_parallelogramPen[i];
            QBrush brush = m_parallelogramBrush[i];
            painter.setPen(pen);
            painter.setBrush(brush);
            QPainterPath path;
            path.moveTo(m_parallelogramVec[i].startX,m_parallelogramVec[i].startY);
            path.lineTo(m_parallelogramVec[i].startX,m_parallelogramVec[i].startY);
            path.lineTo(m_parallelogramVec[i].startX+30,m_parallelogramVec[i].endY);
            path.lineTo(m_parallelogramVec[i].endX,m_parallelogramVec[i].endY);
            path.lineTo(m_parallelogramVec[i].endX-30,m_parallelogramVec[i].startY);
            path.lineTo(m_parallelogramVec[i].startX,m_parallelogramVec[i].startY);
            painter.drawPath(path);
//            painter.fillPath(path,m_brush);
        }

        //绘制之前绘制的菱形(只有上下左右四个方向的绘制)
        for (int i = 0; i < m_diamondVec.size(); ++i) {
            stuDiamond tempDiamod = m_diamondVec[i];
            QBrush brush = m_diamondBrush[i];
            QPen pen = m_diamondPen[i];
            painter.setBrush(brush);
            painter.setPen(pen);
            if (tempDiamod.startY < tempDiamod.endY && abs(tempDiamod.startX - tempDiamod.endX)<30) {
                QPainterPath path;
                path.moveTo(tempDiamod.startX,tempDiamod.startY);
                path.lineTo(tempDiamod.startX,tempDiamod.startY);
                path.lineTo(tempDiamod.startX+40,tempDiamod.startY+(tempDiamod.endY-tempDiamod.startY)/2);
                path.lineTo(tempDiamod.startX,tempDiamod.endY);
                path.lineTo(tempDiamod.startX-40,tempDiamod.startY+(tempDiamod.endY-tempDiamod.startY)/2);
                path.lineTo(tempDiamod.startX,tempDiamod.startY);
                painter.drawPath(path);
//                painter.fillPath(path,m_brush);
            }else if (tempDiamod.startX < tempDiamod.endX && abs(tempDiamod.endY-tempDiamod.startY)<30) {
                QPainterPath path;
                path.moveTo(tempDiamod.startX,tempDiamod.startY);
                path.lineTo(tempDiamod.startX,tempDiamod.startY);
                path.lineTo(tempDiamod.startX+abs(tempDiamod.endX-tempDiamod.startX)/2,tempDiamod.startY-40);
                path.lineTo(tempDiamod.endX,tempDiamod.startY);
                path.lineTo(tempDiamod.startX+abs(tempDiamod.endX-tempDiamod.startX)/2,tempDiamod.startY+40);
                path.lineTo(tempDiamod.startX,tempDiamod.startY);
                painter.drawPath(path);
//                painter.fillPath(path,m_brush);
            }else if (tempDiamod.startY > tempDiamod.endY && abs(tempDiamod.startX - tempDiamod.endX)<30) {
                QPainterPath path;
                path.moveTo(tempDiamod.startX,tempDiamod.startY);
                path.lineTo(tempDiamod.startX,tempDiamod.startY);
                path.lineTo(tempDiamod.startX-40,tempDiamod.startY-(tempDiamod.startY-tempDiamod.endY)/2);
                path.lineTo(tempDiamod.startX,tempDiamod.endY);
                path.lineTo(tempDiamod.startX+40,tempDiamod.startY-(tempDiamod.startY-tempDiamod.endY)/2);
                path.lineTo(tempDiamod.startX,tempDiamod.startY);
                painter.drawPath(path);
//                painter.fillPath(path,m_brush);
            }else if (tempDiamod.startX > tempDiamod.endX && abs(tempDiamod.endY-tempDiamod.startY)<30) {
                QPainterPath path;
                path.moveTo(tempDiamod.startX,tempDiamod.startY);
                path.lineTo(tempDiamod.startX,tempDiamod.startY);
                path.lineTo(tempDiamod.startX-(tempDiamod.startX-tempDiamod.endX)/2,tempDiamod.startY+40);
                path.lineTo(tempDiamod.endX,tempDiamod.startY);
                path.lineTo(tempDiamod.startX-(tempDiamod.startX-tempDiamod.endX)/2,tempDiamod.startY-40);
                path.lineTo(tempDiamod.startX,tempDiamod.startY);
                painter.drawPath(path);
//                painter.fillPath(path,m_brush);
            }
        }
    }
    if (m_isClear) {
        //清除之前绘制的直线后,刷新界面时会绘制上一次最后绘制的直线,短暂停留
        clearLastPaintLine();
        clearLastPaintRectangle();
        clearLastPaintEllipse();
        clearLastPaintDiamond();
        clearLastPaintParallelogram();
        clearLastPaintTrapezoid();
        clearLastPaintTriangle();

        m_isClear = false;
    }
    QWidget::paintEvent(event);
}

#if 0
void Widget::keyPressEvent(QKeyEvent *event)
{
    int type = event->key();
    switch (type) {
    case Qt::Key_1:
        m_type = Widget::line;
        break;
    case Qt::Key_2:
        m_type = Widget::curve;
        break;
    case Qt::Key_3:
        m_type = Widget::rectangle;
        break;
    case Qt::Key_4:
        m_type = Widget::ellipse;
        break;
    case Qt::Key_5:
        m_type = Widget::triangle;
        break;
    case Qt::Key_6:
        m_type = Widget::Trapezoid;
        break;
    case Qt::Key_7:
        m_type = Widget::Parallelogram;
        break;
    case Qt::Key_8:
        m_type = Widget::diamond;
        break;
    default:
        break;
    }
    QWidget::keyPressEvent(event);
}
#endif

void Widget::on_clearBtn_clicked()
{
    m_isClear = true;
    QVector<stuLine>().swap(m_lineVec);//清除之前绘制的所有直线(否则清除后依旧会存在之前绘制的图形)
    QVector<QVector<QPoint>>().swap(m_lines);//清除之前绘制的所有曲线
    QVector<stuRectangle>().swap(m_rectangleVec);//清除之前绘制的矩形
    QVector<stuEllipse>().swap(m_ellipseVec);//清除之前绘制的椭圆
    QVector<stuTriangle>().swap(m_triangleVec);//清除之前绘制三角形
    QVector<stuTrapezoid>().swap(m_trapezoidVec);//清除之前绘制的梯形
    QVector<stuParallelogram>().swap(m_parallelogramVec);//清除之前绘制的平行四边形
    QVector<stuDiamond>().swap(m_diamondVec);//清除之前绘制的菱形

    QVector<QPen>().swap(m_penLineVec);//清空之前绘制直线的画笔
    QVector<QPen>().swap(m_rectanglePen);//清空之前绘制矩形的画笔
    QVector<QPen>().swap(m_ellipsePen);//清空之前绘制椭圆的画笔
    QVector<QPen>().swap(m_trianglePen);//清空之前绘制的三角形的画笔
    QVector<QPen>().swap(m_diamondPen);//清空之前绘制菱形的画笔
    QVector<QPen>().swap(m_parallelogramPen);//清空之前绘制平行四边形的画笔
    QVector<QPen>().swap(m_trapezoidPen);//清空之前绘制梯形的画笔
    QVector<QPen>().swap(m_curvePen);//清空之前绘制曲线的画笔

    QVector<QBrush>().swap(m_rectangleBrush);//清空之前绘制矩形的画刷
    QVector<QBrush>().swap(m_ellipseBrush);//清空之前绘制椭圆的画刷
    QVector<QBrush>().swap(m_diamondBrush);//清空之前绘制菱形的画刷
    QVector<QBrush>().swap(m_parallelogramBrush);//清空之前绘制的平行四边形的画刷
    QVector<QBrush>().swap(m_triangleBrush);//清空之前绘制的三角形的画刷
    QVector<QBrush>().swap(m_trapezoidBrush);//清空之前绘制的梯形的画刷

    QStack<graphicType>().swap(m_typeStack);//清空之前绘制的图形类型
    update();
}

void Widget::on_colorBtn_clicked()
{
    QColor defaultColor = QRgb("#008B8B");
    QColorDialog colorDlg(this);
    colorDlg.setGeometry(200,200,300,280);//此句注释掉之后会再程序运行的时候提示信息
    colorDlg.setWindowTitle(QStringLiteral("颜色选择对话框"));
    colorDlg.setCurrentColor(defaultColor);
    if (colorDlg.exec() == QColorDialog::Accepted) {
        m_color = colorDlg.selectedColor();
    }
    //设置画笔画刷颜色
    setBrushPenColor();
//这种方式创建的颜色对话框不能避免程序运行时,会在应用程序输出栏中输出信息
//    m_color = QColorDialog::getColor(defaultColor,this,QString(QStringLiteral("颜色选择对话框")),QColorDialog::ShowAlphaChannel);
}

void Widget::on_lineTypeCombox_activated(const QString &arg1)
{
    if (arg1.compare(strSolidLine) == 0) {
        m_pen.setStyle(Qt::SolidLine);
    }else if (arg1.compare(strDashLine) == 0) {
        m_pen.setStyle(Qt::DashLine);
    }else if (arg1.compare(strDotLine) == 0) {
        m_pen.setStyle(Qt::DotLine);
    }else if (arg1.compare(strDashDotLine) == 0) {
        m_pen.setStyle(Qt::DashDotLine);
    }else if (arg1.compare(strDashDotDotLine) == 0) {
        m_pen.setStyle(Qt::DashDotDotLine);
    }else if (arg1.compare(strCustomDashLine) == 0) {
        m_pen.setStyle(Qt::CustomDashLine);
    }
}

void Widget::on_checkBox_clicked(bool checked)
{
    (checked == true) ? m_isFill = true : m_isFill = false;
    setBrushPenColor();
}

void Widget::on_spinBox_valueChanged(int arg1)
{
    m_pen.setWidth(arg1);
}

void Widget::on_lineBtn_clicked()
{
    m_type = Widget::line;
}

void Widget::on_curveBtn_clicked()
{
    m_type = Widget::curve;
}

void Widget::on_rectangleBtn_clicked()
{
    m_type = Widget::rectangle;
}

void Widget::on_ellipseBtn_clicked()
{
    m_type = Widget::ellipse;
}

void Widget::on_triangleBtn_clicked()
{
    m_type = Widget::triangle;
}

void Widget::on_parallelogramBtn_clicked()
{
    m_type = Widget::Parallelogram;
}

void Widget::on_TrapezoidBtn_clicked()
{
    m_type = Widget::Trapezoid;
}

void Widget::on_diamondBtn_clicked()
{
    m_type = Widget::diamond;
}

void Widget::on_undoBtn_clicked()
{
    m_type = Widget::noShape;//之前没有加noShape,每次撤销都会剩下最后一个绘制的图形,
    //后来发现撤销时update()的时候最后一次的m_type没有被清空,会重新绘制一下最后的图形,
    //在不能完全撤销的情况下,在重新绘制,之前没有撤销的图像就会自动消失
    if (!m_typeStack.isEmpty()) {
        graphicType &type = m_typeStack.top();
        switch (type) {
            case line:
                if (m_lineVec.size() != 0) {
                    m_lineVec.pop_back();
                    m_penLineVec.pop_back();
                    m_typeStack.pop_back();
                    update();
                }
                break;
            case curve:
                if (m_lines.size() != 0) {
                    m_lines.pop_back();
                    m_curvePen.pop_back();
                    m_typeStack.pop_back();
                    update();
                }
                break;
            case rectangle:
                if (m_rectangleVec.size() != 0) {
                    m_rectangleVec.pop_back();
                    m_rectanglePen.pop_back();
                    m_rectangleBrush.pop_back();
                    m_typeStack.pop_back();
                    update();
                }
                break;
            case ellipse:
                if (m_ellipseVec.size() != 0) {
                    m_ellipseVec.pop_back();
                    m_ellipsePen.pop_back();
                    m_ellipseBrush.pop_back();
                    m_typeStack.pop_back();
                    update();
                }
                break;
            case diamond:
                if (m_diamondVec.size() != 0) {
                    m_diamondVec.pop_back();
                    m_diamondPen.pop_back();
                    m_diamondBrush.pop_back();
                    m_typeStack.pop_back();
                    update();
                }
                break;
            case Parallelogram:
                if (m_parallelogramVec.size() != 0) {
                    m_parallelogramVec.pop_back();
                    m_parallelogramPen.pop_back();
                    m_parallelogramBrush.pop_back();
                    m_typeStack.pop_back();
                    update();
                }
                break;
            case Trapezoid:
                if (m_trapezoidVec.size() != 0) {
                    m_trapezoidVec.pop_back();
                    m_trapezoidBrush.pop_back();
                    m_trapezoidPen.pop_back();
                    m_typeStack.pop_back();
                    update();
                }
                break;
            case triangle:
                if (m_triangleVec.size() != 0) {
                    m_triangleVec.pop_back();
                    m_triangleBrush.pop_back();
                    m_trianglePen.pop_back();
                    m_typeStack.pop_back();
                    update();
                }
                break;
            default:break;
        }
    }else {
        qDebug()<<QStringLiteral("之前绘制的图形已经撤销完!");
    }
}

void Widget::on_screenshotSaveBtn_clicked()
{
    Screenshot::getInstance()->showFullScreen();//调用全屏显示的时候会调用showevent事件
}

screenshot.h

#ifndef SCREENSHOT_H
#define SCREENSHOT_H

#include <QWidget>
#include <QPixmap>

/********************************************
        ======功能描述:=======
        1.点击截图按钮出现截图蒙层,
        2.按住鼠标选择矩形区域截图,
        3.拖动选中的矩形截图区域,
        4.保存矩形区域的截图,
        5.按下f键保存全屏截图,
        6.另存为和取消截图。
********************************************/

class Screenshot:public QWidget
{
Q_OBJECT
    Screenshot();
public:
    static Screenshot * getInstance();//获取类对象

private:
    void correctStartEndCoordinate(QPoint &startPos,QPoint &endPos);//纠正左上和右下坐标
    void displayScreenshotText(QPainter &painter,QString text);//分情况显示截图的文本信息
    void createSaveBtn();//创建选中区域后保存取消按钮
    void setBtnWidgetPos();//分情况设置按钮对话框的位置
    void setMaxSize(int width,int height);//设置最大的宽度,最大的高度
    void saveCaptrueFullScreen();//保存截取全屏
    void moveUpdateTopleftBottomRight(QPoint offset);//移动的时候更新左上坐标和右下坐标
protected:
    void mousePressEvent(QMouseEvent *event);//鼠标按下
    void mouseMoveEvent(QMouseEvent *event);//鼠标移动
    void mouseReleaseEvent(QMouseEvent *event);//鼠标释放
    void showEvent(QShowEvent *event);//创建蒙层,调用全屏显示的时候,该函数被触发
    void paintEvent(QPaintEvent *event);//绘制
    void keyPressEvent(QKeyEvent *event);//键盘事件,当按下f截全屏
private slots:
    void onSaveBtn();//保存截图
    void onCancelBtn();//取消截图
    void onSaveAsBtn();//截图另存为
private:
    QPixmap                     *m_widgetBack;//截图的蒙层背景
    QPixmap                     *m_fullMap;//抓取的全屏图片
    bool                        m_isScreenshot;//是否是截屏
    QPoint                      m_startPos;//开始点
    QPoint                      m_endPos;//结束点
    QPoint                      m_topleft;//左上角坐标
    QPoint                      m_bottomRight;//右上坐标
    QWidget                     *m_btnWidget;//保存按钮的窗口
    int                         m_maxWidth;//截图最大的宽度
    int                         m_maxHeight;//截图最大的高度
    QPoint                      m_startMove;//开始拖动的点
    static QScopedPointer<Screenshot> self;//暂存类对象
};

#endif // SCREENSHOT_H

screenshot.cpp

#include "screenshot.h"
#include <QPainter>
#include <QMutex>
#include <QMutexLocker>
#include <QGuiApplication>
#include <QApplication>
#include <QDesktopWidget>
#include <QScreen>
#include <QMouseEvent>
#include <QPushButton>
#include <QHBoxLayout>
#include <QDateTime>
#include <QFileDialog>
#include <QDebug>

QScopedPointer<Screenshot> Screenshot::self;
Screenshot::Screenshot()
:QWidget()
{

}

Screenshot *Screenshot::getInstance()
{
    if (self.isNull()) {
        static QMutex mutex;
        QMutexLocker locker(&mutex);
        if (self.isNull()) {
            self.reset(new Screenshot);
        }
    }
    return self.take();
}

void Screenshot::correctStartEndCoordinate(QPoint &startPos, QPoint &endPos)
{
    if (startPos.x() < endPos.x() && startPos.y() < endPos.y()) {
        m_topleft = startPos;
        m_bottomRight = endPos;
    }else if (startPos.x() < endPos.x() && startPos.y() > endPos.y()) {
        m_topleft.setX(startPos.x());
        m_topleft.setY(endPos.y());
        m_bottomRight.setX(endPos.x());
        m_bottomRight.setY(startPos.y());
    }else if (startPos.x() > endPos.x() && startPos.y() > endPos.y()) {
        m_topleft = endPos;
        m_bottomRight = startPos;
    }else if (startPos.x() > endPos.x() && startPos.y() < endPos.y()) {
        m_topleft.setX(endPos.x());
        m_topleft.setY(startPos.y());
        m_bottomRight.setX(startPos.x());
        m_bottomRight.setY(endPos.y());
    }
}

void Screenshot::displayScreenshotText(QPainter &painter,QString text)
{
    if ((m_topleft.y() > 0 && m_topleft.y() < 9) || m_topleft.y() ==0) {
        painter.drawText(m_topleft.x() + 2,m_topleft.y() + 16,text);
    }else {
        painter.drawText(m_topleft.x() + 2,m_topleft.y() - 10,text);
    }
}

void Screenshot::createSaveBtn()
{
    m_btnWidget = new QWidget();
    m_btnWidget->setWindowFlag(Qt::FramelessWindowHint);
    //分情况设置按钮对话框的位置,当m_bottomRight.y()为最大高度,按钮对话框位于内部
    setBtnWidgetPos();
    QPushButton *saveBtn = new QPushButton(QStringLiteral("保存"),m_btnWidget);
    QPushButton *cancelBtn = new QPushButton(QStringLiteral("取消"),m_btnWidget);
    QPushButton *saveAsBtn = new QPushButton(QStringLiteral("另存为:"),m_btnWidget);
    saveBtn->setFixedSize(80,30);
    cancelBtn->setFixedSize(80,30);
    saveAsBtn->setFixedSize(80,30);
    QHBoxLayout *hLayout = new QHBoxLayout(m_btnWidget);
    hLayout->setSpacing(0);
    hLayout->setContentsMargins(0,0,0,0);
    hLayout->addWidget(cancelBtn);
    hLayout->addWidget(saveAsBtn);
    hLayout->addWidget(saveBtn);

    m_btnWidget->show();

    connect(saveBtn,&QPushButton::clicked,this,&Screenshot::onSaveBtn);
    connect(cancelBtn,&QPushButton::clicked,this,&Screenshot::onCancelBtn);
    connect(saveAsBtn,&QPushButton::clicked,this,&Screenshot::onSaveAsBtn);
}

void Screenshot::setBtnWidgetPos()
{
    if (m_bottomRight.y() == m_maxHeight || (m_bottomRight.y() > m_maxHeight - 30 && m_bottomRight.y() < m_maxHeight)) {
        m_btnWidget->setGeometry(m_bottomRight.x() - 240,m_bottomRight.y() - 32,240,30);
    }else {
        m_btnWidget->setGeometry(m_bottomRight.x() - 240,m_bottomRight.y() + 2,240,30);
    }
}

void Screenshot::setMaxSize(int width, int height)
{
    m_maxWidth = width;
    m_maxHeight = height;
}

void Screenshot::saveCaptrueFullScreen()
{
    QString strFileName = QString("%1/picture-%2.png").arg(qApp->applicationDirPath()).arg(QDateTime::currentDateTime().toString("yyyy-MM-dd-HH-mm-ss"));
    m_fullMap->save(strFileName,"png");//全屏保存
    close();
}

void Screenshot::moveUpdateTopleftBottomRight(QPoint offset)
{
    m_topleft += offset;
    m_bottomRight += offset;
    if (m_topleft.x() < 0) {
        m_bottomRight.setX(m_bottomRight.x() - m_topleft.x());
        m_topleft.setX(0);
    }else if (m_topleft.y() < 0) {
        m_bottomRight.setY(m_bottomRight.y() - m_topleft.y());
        m_topleft.setY(0);
    }else if (m_bottomRight.x() > m_maxWidth) {
        m_topleft.setX(m_topleft.x() - (m_bottomRight.x() - m_maxWidth));
        m_bottomRight.setX(m_maxWidth);
    }else if (m_bottomRight.y() > m_maxHeight) {
        m_topleft.setY(m_topleft.y() - (m_bottomRight.y() - m_maxHeight));
        m_bottomRight.setY(m_maxHeight);
    }
}

void Screenshot::mousePressEvent(QMouseEvent *event)
{
    if (m_isScreenshot && event->button() == Qt::LeftButton) {
        m_startPos = event->pos();
    }else if (!m_isScreenshot) {
        if (QRect(m_topleft,m_bottomRight).contains(event->pos())) {
            m_startMove = event->pos();
            setCursor(Qt::SizeAllCursor);
            m_btnWidget->hide();
        }else {
            m_startPos = event->pos();
            m_isScreenshot = true;
        }
    }
    QWidget::mousePressEvent(event);
}

void Screenshot::mouseMoveEvent(QMouseEvent *event)
{
    if (event->buttons() == Qt::LeftButton && m_isScreenshot) {
        m_endPos = event->pos();
        correctStartEndCoordinate(m_startPos,m_endPos);
    }else if (!m_isScreenshot && event->buttons() == Qt::LeftButton) {
        QPoint offPos = event->pos() - m_startMove;
        moveUpdateTopleftBottomRight(offPos);
        m_startMove = event->pos();
    }
    update();
}

void Screenshot::mouseReleaseEvent(QMouseEvent *event)
{
    if (m_isScreenshot) {
        m_isScreenshot = false;
        createSaveBtn();
    }else {
        setCursor(Qt::ArrowCursor);
        setBtnWidgetPos();
        m_btnWidget->show();
    }
    QWidget::mouseReleaseEvent(event);
}

void Screenshot::showEvent(QShowEvent *event)
{
    m_isScreenshot = true;
    m_btnWidget = nullptr;//赋初值,避免野指针
    //相当于获取桌面的快照
    QScreen *screen = QGuiApplication::primaryScreen();
    m_fullMap = new QPixmap();
    *m_fullMap = screen->grabWindow(QApplication::desktop()->winId(),0,0,QApplication::desktop()->size().width(),QApplication::desktop()->size().height());

    //创建桌面大小的蒙层
    QPixmap *backMap = new QPixmap(QApplication::desktop()->size());
    backMap->fill(QColor(160,160,160,200));

    //在桌面大小的图片上绘制蒙层(作为中间的一层,这个必须有,否则直接在全屏的图片上绘制蒙层,截图后的图片也会含有蒙层)
    m_widgetBack = new QPixmap(*m_fullMap);
    QPainter paint(m_widgetBack);
    paint.drawPixmap(0,0,*backMap);
    setMaxSize(QApplication::desktop()->size().width(),QApplication::desktop()->size().height());
}

void Screenshot::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    QPen pen;
    pen.setWidth(4);
    pen.setColor(QColor(Qt::darkYellow));
    pen.setStyle(Qt::DashLine);
    painter.setPen(pen);
    painter.drawPixmap(0,0,*m_widgetBack);

    if (qAbs(m_topleft.x() - m_bottomRight.x()) != 0 && qAbs(m_topleft.y() - m_bottomRight.y()) != 0) {
        painter.drawPixmap(m_topleft,m_fullMap->copy(QRect(m_topleft,m_bottomRight)));
        painter.drawRect(QRect(m_topleft,m_bottomRight));
        //判断左上角的y坐标的位置,分情况显示文本
        QString strText = QStringLiteral("截图的大小:%1x%2 - %3x%4,(%5x%6)")
        .arg(m_topleft.x()).arg(m_topleft.y()).arg(m_bottomRight.x()).arg(m_bottomRight.y())
        .arg(m_bottomRight.x()-m_topleft.x()).arg(m_bottomRight.y()-m_topleft.y());
        displayScreenshotText(painter,strText);
    }

    QWidget::paintEvent(event);
}

void Screenshot::keyPressEvent(QKeyEvent *event)
{
    if (event->key() == Qt::Key_F) {
        saveCaptrueFullScreen();
    }else if (event->key() == Qt::Key_Escape) {
        onCancelBtn();
    }
    QWidget::keyPressEvent(event);
}

void Screenshot::onSaveBtn()
{
    QString strFileName = QString("%1/pix-%2.png").arg(qApp->applicationDirPath()).arg(QDateTime::currentDateTime().toString("yyyy-MM-dd-hh-mm-ss"));
    m_fullMap->copy(QRect(m_topleft,m_bottomRight)).save(strFileName,"png");//保存截图时选中的区域
    m_btnWidget->close();//虽然效果上可行,但是感觉怪怪的
    close();
}

void Screenshot::onCancelBtn()
{
    close();
    if (m_btnWidget) {//此处若是指针m_btnWidget没有赋初值,就会存在野指针,从而导致程序崩溃
        m_btnWidget->close();
    }
}

void Screenshot::onSaveAsBtn()
{
    QString strFileName = QFileDialog::getSaveFileName(this,QStringLiteral("另存为"),qApp->applicationDirPath(),"Images(*.png *.jpg)");
    m_fullMap->copy(QRect(m_topleft,m_bottomRight)).save(strFileName,"png");
    m_btnWidget->close();
    close();
}

以上便是所有的实现代码。

  • 5
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值