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_NAMESPACEstruct stuLine//直线
{int     startX;//按下点的xint     startY;//按下点的yint     endX;//终点的x(移动过程中的点,释放时的点)int     endY;//终点的y(移动过程中的点,释放时的点)
};struct stuRectangle//矩形
{int     startX;//按下点的xint     startY;//按下点的yint     width;//矩形宽int     height;//矩形高
};struct stuEllipse//圆或者椭圆
{int     startX;//按下点的xint     startY;//按下点的yint     width;//矩形宽int     height;//矩形高
};struct stuTriangle//三角形(使用路径绘制)
{int     startX;//按下点的xint     startY;//按下点的yint     endX;//终点的x(移动过程中的点,释放时的点)int     endY;//终点的y(移动过程中的点,释放时的点)
};struct stuParallelogram//平行四边形(使用路径绘制)
{int     startX;//按下点的xint     startY;//按下点的yint     endX;//终点的x(移动过程中的点,释放时的点)int     endY;//终点的y(移动过程中的点,释放时的点)
};struct stuTrapezoid//梯形(路径绘制)
{int     startX;//按下点的xint     startY;//按下点的yint     endX;//终点的x(移动过程中的点,释放时的点)int     endY;//终点的y(移动过程中的点,释放时的点)
};struct stuDiamond//菱形(路径绘制)
{int     startX;//按下点的xint     startY;//按下点的yint     endX;//终点的x(移动过程中的点,释放时的点)int     endY;//终点的y(移动过程中的点,释放时的点)
};class Widget : public QWidget
{Q_OBJECTenum 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 0QPainter 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]);}}
#endifQPainter 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 0painter.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);}#endifif (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 1QPainterPath 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 0QPointF 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 1QPainterPath 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);
}
#endifvoid 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_OBJECTScreenshot();
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();
}

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/523819.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring基础环境搭建

创建一个父工程springdubbo&#xff0c;3个子工程分别为服务端provider&#xff0c;客户端consumer &#xff0c;接口api 选择都选择maven quickstart即可 在main目录下面创建resources文件夹&#xff0c;并且让idea识别&#xff0c;选择中右击&#xff1a; 给父工程添加依赖…

VMware vSphere 6.0 虚拟机运维常见问题排除

戳蓝字“CSDN云计算”关注我们哦&#xff01;技术头条&#xff1a;干货、简洁、多维全面。更多云计算精华知识尽在眼前&#xff0c;get要点、solve难题&#xff0c;统统不在话下&#xff01;当您将VMware vSphere 6.0虚拟化平台架构中的vCenter、ESXi主机、Data Center、群集完…

Windows下Zookeeper启动zkServer.cmd闪退问题的解决方案

本人今天在使用RPC的过程中使用Zookeeper作为中间节点服务器。在windows中启动Zookeeper 在windows启动Zookeeper双击zkServer.cmd&#xff08;但是需要保证安装了java环境&#xff09; 但是我单击启动的时候闪退&#xff1a;原因可以找到&#xff0c;编辑工具打开zkServer.c…

2019 年 Q1 全球云基础设施市场份额揭晓,AWS继续领跑市场;Mesos官方回应Twitter“抛弃”Mesos……...

戳蓝字“CSDN云计算”关注我们哦&#xff01;重磅先知 2019 年 Q1 全球云基础设施市场份额揭晓Mesos官方回应Twitter“抛弃”Mesos国内唯一&#xff0c;阿里云论文连续两年入选国际数据库顶级会议SIGMOD甲骨文中国研发中心大裁员&#xff1a;离职赔偿N6重磅快报2019 年 Q1 全球…

微电台│Get产品信息管理指南,和客户谈一场全渠道恋爱!

戳蓝字“CSDN云计算”关注我们哦&#xff01;▷ Informatica微电台004期 ◁楼下小谭撩数据&#xff08;隔壁的老王已经回到隔壁啦~&#xff09;如何使用产品信息管理与客户谈一场全渠道的恋爱&#xff1f;▼莫文蔚的阴天&#xff0c;孙燕姿的雨天&#xff0c;周杰伦的晴天都不如…

漫话:如何给女朋友解释灭霸的指响并不是真随机消灭半数宇宙人口的?

戳蓝字“CSDN云计算”关注我们哦&#xff01;技术头条&#xff1a;干货、简洁、多维全面。更多云计算精华知识尽在眼前&#xff0c;get要点、solve难题&#xff0c;统统不在话下&#xff01;周末&#xff0c;陪女朋友去电影院看了《复仇者联盟4&#xff1a;终局之战》&#xff…

plsql常用快捷键

路径&#xff1a; D:\software\PLSQL Developer\PlugIns\shortcuts.txtplsql使用技巧 1、类SQL PLUS窗口:File->New->Command Window&#xff0c;这个类似于oracle的客户端工具sql plus&#xff0c;但比它好用多了。 2、设置关键字自动大写:Tools->Preferences->…

数据库不适合上容器云?| 技术头条

戳蓝字“CSDN云计算”关注我们哦&#xff01;技术头条&#xff1a;干货、简洁、多维全面。更多云计算精华知识尽在眼前&#xff0c;get要点、solve难题&#xff0c;统统不在话下&#xff01;Docker 在企业环境的应用端具有很大的潜力&#xff0c;在这一点上我想大家是有目共睹的…

【Git】fatal: bad boolean config value ‘true~‘ for ‘core.longpaths‘

windwos操作系统git config设置错了参数值&#xff0c;解决方法。 出现原因 在拉取代码时&#xff0c;仓库中存在文件名过长得文件&#xff0c;拉取报错了“filename too long” 解决 git config --system core.longpaths true结果在复制命令时&#xff0c;粘贴到命令行多了一…

【数据分析】盘点五一期间最受欢迎的几个景区

戳蓝字“CSDN云计算”关注我们哦&#xff01;五一假期已经结束&#xff0c;小伙伴是不是都还没有玩过瘾&#xff1f;但是没办法&#xff0c;还有很多bug等着我们去写&#xff0c;同样还有需要money需要我们去赚。为了生活总的拼搏。今年五一放了四天假&#xff0c;很多人不再只…

SonarQube代码质量管理平台C++插件sonar-cxx的安装

gblfy推荐了一个好的可替代CFamily插件&#xff0c; sonar-cxx插件&#xff0c;听闻插件作者就是看不惯CFamily的收费&#xff0c;自己写了个开源的&#xff0c; 更牛逼的插件&#xff0c;开源地址 https://github.com/SonarOpenCommunity/sonar-cxx这是我使用插件后的图片&am…

qt提升控件之后,编译报错

引言 自定义的控件&#xff0c;在ui文件中将控件提升为自定义的控件&#xff0c;提升的时候没有指明提升的头文件的相对路径或者绝对路径&#xff0c;导致编译的时候无法找到相应的头文件。 解决方法 1.在被提升的类的头文件前添加本机电脑所在的相对路径&#xff1b; 2.在被…

Spark精华问答 | 学Spark究竟有什么用?

戳蓝字“CSDN云计算”关注我们哦&#xff01;为什么要学习Spark&#xff1f;作为一个用来实现快速而通用的集群计算的平台。扩展广泛使用的MapReduce计算模型&#xff0c;而且高效地支持更多的计算模式&#xff0c;包括交互式查询和流处理。Spark的一个重要特点就是能够在内存中…

SecureCRT 设置护眼最佳方案 的字体及颜色

SecureCRT远程连接Linux服务器 文章目录1. 选择全局选项2. 选择默认会话-【编辑默认设置】3. 选择仿真-【终端选择Linux】4. 选择外观-【当前颜色方案&#xff08;白/黑&#xff09;】 -【字符编码】5. 字体修改-点击字体6. 选择字体及大小7. 关闭重启SecureCRT8. 效果图&#…

SecureCRT 免安装、绿色版、免费版本

SecureCRT远程连接Linux服务器 文章目录1. 下载软件2. 解压软件3. 双击运行4. 选择SecureCRT5. 图标点击&#xff0c;输入用户名6. 添加密码&#xff0c;点击确定7. 连接成功1. 下载软件 链接https://pan.baidu.com/s/1vv40uI_0uwIagPGm7FS9_g 提取码t32h 2. 解压软件 3. 双击…

GitHub重大更新即将加入免费软件包管理服务;钉钉社区因出现违规内容将停更整改一个月;Uber上市,定价为45美元……...

关注并标星星CSDN云计算极客头条&#xff1a;速递、最新、绝对有料。这里有企业新动、这里有业界要闻&#xff0c;打起十二分精神&#xff0c;紧跟fashion你可以的&#xff01;每周三次&#xff0c;打卡即read更快、更全了解泛云圈精彩newsgo go go永安行共享电动汽车&#xff…

SecureCRT 文件下载上传

SecureCRT远程连接Linux服务器 文章目录1. 点击SecureFX图标2. 填写密码3. 窗口简要说明4. 上传文件5. 下载文件6. 第二种方案(建议使用)&#xff1a;7. 拖拽文件或目录8. 效果图1. 点击SecureFX图标 2. 填写密码 3. 窗口简要说明 4. 上传文件 5. 下载文件 6. 第二种方案(建议使…

《复联4》| 生活需要漫威这块糖

戳蓝字“CSDN云计算”关注我们哦&#xff01;漫威电影宇宙&#xff0c;历时11年&#xff0c;经历了21部电影&#xff0c;终于迎来了最终章。有人问如果没看过复联1、2、3可以去看吗&#xff1f;只看过钢铁侠没接触过复联可以去看吗&#xff1f;......看当然是可以看的&#xff…

企业实战02:Oracle数据库的安装和卸载

Oracle数据库专栏 文章目录一、 Oracle安装1.1. Oracle下载链接&#xff1a;1.2. 解压到一个文件夹中1.3. 百度云解压包&#xff1a;二、Oracle安装流程2.1. 以管理员身份运行2.2. 下图忽略2.3. 开始安装2.4. 选择-【是】2.5. 不勾选邮箱2.6. 选择【是】2.7. 选择创建和配置数据…

10 种最流行的 Web 挖掘工具 | 程序员硬核评测

戳蓝字“CSDN云计算”关注我们哦&#xff01; 程序员硬核评测&#xff1a;客观、高效、不说软话。无论是技术质量、性能水平&#xff0c;还是工具筛选&#xff0c;一测便知&#xff01;作者 | prowebscrapers blog译者 | 高级农民工责编 | 胡巍巍本文经授权转载自高级农民工互…