引言
实现可以选择线型,线宽,颜色,是否填充图形来绘制各种常见的图形,同时可以选择矩形区域来实现截图。
效果
绘图的效果如上,截图的效果:
实现
项目使用的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();
}
以上便是所有的实现代码。