Qt实现截图功能(C++/仿微信风格)

效果演示:

该截图功能仅需引入screenshotwidget.h与screenshotwidget.cpp即可使用。

一、引用示例如下:

1、在需要引用的头文件中include"screenshotwidget.h",并创建ScreenShotWidget变量

//widget.h
#include"screenshotwidget.h"

ScreenShotWidget *widget

2、创建一个按钮,并在按钮的点击响应函数中加入以下代码即可完成引用

//widget.cpp
void Widget::on_pushButton_clicked()
{
    if(widget!=nullptr){
        widget->deleteLater();
        widget=nullptr;
    }
    widget=new ScreenShotWidget();
    widget->showFullScreen();
}

二、截图模块代码如下

screenshotwidget.h

#ifndef SCREENSHOTWIDGET_H
#define SCREENSHOTWIDGET_H

#include <QApplication>
#include <QCoreApplication>
#include <QWidget>
#include <QMouseEvent>
#include <QPainter>
#include <QFileDialog>
#include <QMessageBox>
#include <QTimer>
#include <QScreen>
#include <QDesktopWidget>
#include <QPen>
#include <QPushButton>
#include <QDateTime>
#include <QTime>
#include <QPixmap>
#include <QThread>
#include <QDebug>
#include <QLabel>

class ScreenShotWidget : public QWidget
{
    Q_OBJECT
public:
    ScreenShotWidget(QWidget *parent = nullptr);
protected:
    //鼠标按下事件
    void mousePressEvent(QMouseEvent *event) override;
    //鼠标移动事件
    void mouseMoveEvent(QMouseEvent *event) override;
    //鼠标松开事件
    void mouseReleaseEvent(QMouseEvent *event) override;
    //绘制边框事件
    void paintEvent(QPaintEvent *event) override;
private slots:
    void on_buttonSave_Clicked();
    void on_buttonCancel_Clicked();
private:
    QPoint getPointInWhichSqure(QPoint point);

private:
    QPushButton *buttonSave,*buttonCancel;
    QLabel *lblHeightWidth;
    QLabel *lblMagnifyGlass;
    QPainter m_painter;
    QPoint m_startPos,m_endPos;           //用于记录生成的截图区域
    QPoint m_oldPos,m_distancePos;     //用于拖拽截图区域
    bool m_screenshot_active;

    QPoint m_topLeft;
    QPoint m_topRight;
    QPoint m_bottomLeft;
    QPoint m_bottomRight;
    QPoint m_topCenter;
    QPoint m_bottomCenter;
    QPoint m_leftCenter;
    QPoint m_rightCenter;
    int m_cursorMode;
};

#endif // SCREENSHOTWIDGET_H

screenshotwidget.cpp

#include "screenshotwidget.h"

ScreenShotWidget::ScreenShotWidget(QWidget *parent) :
    QWidget(parent)
{
    //初始化截图激活标志
    m_screenshot_active=false;
    //设置窗口,无边框,顶部显示
    setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
    setWindowModality(Qt::ApplicationModal);
    //窗口背景为透明
    setAttribute(Qt::WA_TranslucentBackground);
    //设置窗口跟踪鼠标移动事件
    setMouseTracking(true);
    //设置保存、取消按钮以及长宽label并暂时隐藏
    buttonSave=new QPushButton(this);
    buttonSave->setParent(this);
    buttonSave->setFixedSize(35,30);
    buttonSave->setText("√");
    buttonSave->setStyleSheet("QPushButton {font-size:16pt; color:green; font-weight:800;}");
    buttonSave->setVisible(false);
    buttonCancel=new QPushButton(this);
    buttonCancel->setParent(this);
    buttonCancel->setFixedSize(35,30);
    buttonCancel->setText("✖");
    buttonCancel->setStyleSheet("QPushButton {font-size:20pt; color:red;font-weight:100;}");
    buttonCancel->setVisible(false);
    lblHeightWidth=new QLabel(this);
    lblHeightWidth->setParent(this);
    lblHeightWidth->setFixedSize(100,10);
    lblHeightWidth->setStyleSheet("QLabel {color:white;}");
    lblHeightWidth->setVisible(false);
    //设置放大镜
    lblMagnifyGlass=new QLabel(this);
    lblMagnifyGlass->setParent(this);
    lblMagnifyGlass->setFixedSize(100,100);
    lblMagnifyGlass->setVisible(true);
    lblMagnifyGlass->setText("wo zai zhe");
    //设置鼠标光标模式为十字
    setCursor(Qt::CursorShape::CrossCursor);
    //连接按钮的信号槽
    connect(this->buttonSave,SIGNAL(clicked()),this,SLOT(on_buttonSave_Clicked()));
    connect(this->buttonCancel,SIGNAL(clicked()),this,SLOT(on_buttonCancel_Clicked()));
}

void ScreenShotWidget::mousePressEvent(QMouseEvent *event)
{
    if(event->button()==Qt::LeftButton)
    {
        QRect rect(m_startPos,m_endPos);
        if((rect.contains(event->pos())||m_cursorMode!=0)&&m_startPos!=m_endPos){
            m_oldPos=event->pos();
        }
        else if(m_startPos==m_endPos){
            //记录鼠标点击的起始位置
            m_startPos = event->pos();
            //截图激活标志
            m_screenshot_active=true;
        }
    }
    else if(event->button()==Qt::RightButton)//重新截图
    {
        if(m_endPos.isNull())
            on_buttonCancel_Clicked();
        m_startPos=QPoint(0,0);
        m_endPos=QPoint(0,0);
        buttonSave->setVisible(false);
        buttonCancel->setVisible(false);
        lblHeightWidth->setVisible(false);
        setCursor(Qt::CursorShape::CrossCursor);
        update();
    }
}

void ScreenShotWidget::mouseMoveEvent(QMouseEvent *event)
{
    QRect rect(m_startPos,m_endPos);
    QPoint point=getPointInWhichSqure(event->pos());
    //截图后不点击鼠标时的光标更新
    if(!m_screenshot_active && m_startPos!=m_endPos && !event->buttons()){
        if(point==m_topLeft) {setCursor(Qt::CursorShape::SizeFDiagCursor);m_cursorMode=1;}
        else if(point==m_topRight) {setCursor(Qt::CursorShape::SizeBDiagCursor);m_cursorMode=2;}
        else if(point==m_bottomLeft) {setCursor(Qt::CursorShape::SizeBDiagCursor);m_cursorMode=3;}
        else if(point==m_bottomRight) {setCursor(Qt::CursorShape::SizeFDiagCursor);m_cursorMode=4;}
        else if(point==m_topCenter) {setCursor(Qt::CursorShape::SizeVerCursor);m_cursorMode=5;}
        else if(point==m_bottomCenter) {setCursor(Qt::CursorShape::SizeVerCursor);m_cursorMode=6;}
        else if(point==m_leftCenter) {setCursor(Qt::CursorShape::SizeHorCursor);m_cursorMode=7;}
        else if(point==m_rightCenter) {setCursor(Qt::CursorShape::SizeHorCursor);m_cursorMode=8;}
        else if(rect.contains(event->pos())) {setCursor(Qt::CursorShape::ClosedHandCursor);m_cursorMode=9;}
        else {setCursor(Qt::CursorShape::ArrowCursor);m_cursorMode=0;}
    }
    //鼠标左键按下
    if(event->buttons() & Qt::LeftButton)
    {
        //截图中位置更新
        if(m_screenshot_active){
            m_endPos = event->pos();
        }
        //拖动已截图区域
        if(rect.contains(event->pos()) && !m_screenshot_active &&cursor().shape()==Qt::ClosedHandCursor){
            m_distancePos=event->pos()-m_oldPos;
            m_oldPos=event->pos();
            m_startPos=m_startPos+m_distancePos;
            m_endPos=m_endPos+m_distancePos;
            //边界条件限制
            if(m_startPos.x()<=0){m_startPos.rx()=0;m_endPos.rx()=m_endPos.x()-m_distancePos.x();}
            if(m_startPos.y()<=0){m_startPos.ry()=0;m_endPos.ry()=m_endPos.y()-m_distancePos.y();}
            if(m_endPos.x()>=this->width()){m_endPos.rx()=this->width();m_startPos.rx()=m_startPos.x()-m_distancePos.x();}
            if(m_endPos.y()>=this->height()){m_endPos.ry()=this->height();m_startPos.ry()=m_startPos.y()-m_distancePos.y();}
        }
        else if(cursor().shape()==Qt::SizeFDiagCursor)
        {
            if(m_cursorMode==1){
                m_distancePos=event->pos()-m_oldPos;
                m_oldPos=event->pos();
                m_startPos=m_startPos+m_distancePos;
            }
            if(m_cursorMode==4){
                m_distancePos=event->pos()-m_oldPos;
                m_oldPos=event->pos();
                m_endPos=m_endPos+m_distancePos;
            }
        }
        else if(cursor().shape()==Qt::SizeBDiagCursor)
        {
            if(m_cursorMode==2){
                m_distancePos=event->pos()-m_oldPos;
                m_oldPos=event->pos();
                m_startPos.ry()=m_startPos.y()+m_distancePos.y();
                m_endPos.rx()=m_endPos.x()+m_distancePos.x();
            }
            if(m_cursorMode==3){
                m_distancePos=event->pos()-m_oldPos;
                m_oldPos=event->pos();
                m_startPos.rx()=m_startPos.x()+m_distancePos.x();
                m_endPos.ry()=m_endPos.y()+m_distancePos.y();
            }
        }
        else if(cursor().shape()==Qt::SizeHorCursor)
        {
            if(m_cursorMode==7){
                m_distancePos=event->pos()-m_oldPos;
                m_oldPos=event->pos();
                m_startPos.rx()=m_startPos.x()+m_distancePos.x();
            }
            if(m_cursorMode==8){
                m_distancePos=event->pos()-m_oldPos;
                m_oldPos=event->pos();
                m_endPos.rx()=m_endPos.x()+m_distancePos.x();
            }
        }
        else if(cursor().shape()==Qt::SizeVerCursor)
        {
            if(m_cursorMode==5){
                m_distancePos=event->pos()-m_oldPos;
                m_oldPos=event->pos();
                m_startPos.ry()=m_startPos.y()+m_distancePos.y();
            }
            if(m_cursorMode==6){
                m_distancePos=event->pos()-m_oldPos;
                m_oldPos=event->pos();
                m_endPos.ry()=m_endPos.y()+m_distancePos.y();
            }
        }
        update();
    }

}

void ScreenShotWidget::mouseReleaseEvent(QMouseEvent *event)
{
    Q_UNUSED(event);
    if (m_screenshot_active) {
        m_screenshot_active=false;
        if (m_endPos != m_startPos) {
            //弹出保存/取消按钮
            buttonSave->setVisible(true);
            buttonCancel->setVisible(true);
        }
    }
}

void ScreenShotWidget::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);
    QPainter painter(this);
    painter.fillRect(rect(),QColor(128,128,128,128));
    QColor color(11,218,81);
    QPen pen(color,1,Qt::SolidLine);
    painter.setPen(pen);
    //边界条件限制
    if(m_startPos.x()>=m_endPos.x())m_endPos.rx()=m_startPos.x();
    if(m_startPos.y()>=m_endPos.y())m_endPos.ry()=m_startPos.y();
    //画矩形,并将内部置为透明
    QRect rect(m_startPos, m_endPos);
    painter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
    painter.fillRect(rect,QColor(0,0,0,0));
    painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
    painter.drawRect(rect.normalized());
    // 获取矩形的四个顶点和四条边的中点
    m_topLeft=QPoint(rect.left(),rect.top());
    m_topRight=QPoint(rect.right()+1,rect.top());
    m_bottomLeft=QPoint(rect.left(),rect.bottom()+1);
    m_bottomRight=QPoint(rect.right()+1,rect.bottom()+1);
    m_topCenter=QPoint(rect.center().x(), rect.top());
    m_bottomCenter=QPoint(rect.center().x(), rect.bottom()+1);
    m_leftCenter=QPoint(rect.left(), rect.center().y());
    m_rightCenter=QPoint(rect.right()+1, rect.center().y()+1);

    // 定义一个小矩形的大小,用来画实心点
    int pointSize = 5;
    QRect pointRect(0, 0, pointSize, pointSize);

    // 在每个点的位置画一个小矩形,作为实心点
    pointRect.moveCenter(m_topLeft);
    painter.fillRect(pointRect, color);
    pointRect.moveCenter(m_topRight);
    painter.fillRect(pointRect, color);
    pointRect.moveCenter(m_bottomLeft);
    painter.fillRect(pointRect, color);
    pointRect.moveCenter(m_bottomRight);
    painter.fillRect(pointRect, color);
    pointRect.moveCenter(m_topCenter);
    painter.fillRect(pointRect, color);
    pointRect.moveCenter(m_bottomCenter);
    painter.fillRect(pointRect, color);
    pointRect.moveCenter(m_leftCenter);
    painter.fillRect(pointRect, color);
    pointRect.moveCenter(m_rightCenter);
    painter.fillRect(pointRect, color);
    //显示放大镜
    if(cursor().shape()!=Qt::ClosedHandCursor)
    {
        QRect cursorRect(QCursor::pos().x()-25,QCursor::pos().y()-25,51,51);
        QScreen *screen=QGuiApplication::primaryScreen();
        QPixmap cursorPixmap=screen->grabWindow(QApplication::desktop()->winId(),cursorRect.x(),cursorRect.y(),cursorRect.width(),cursorRect.height());
        cursorPixmap=cursorPixmap.scaled(cursorPixmap.width()*2,cursorPixmap.height()*2,Qt::KeepAspectRatio);
        QPoint startPoint(QCursor::pos().x()+26,QCursor::pos().y()+26);
        painter.drawPixmap(startPoint.x(),startPoint.y(),cursorPixmap.width(),cursorPixmap.height(),cursorPixmap);
        painter.drawRect(startPoint.x(),startPoint.y(),cursorPixmap.width(),cursorPixmap.height());
        QPen pen2(color,2,Qt::SolidLine);
        painter.setPen(pen2);
        painter.drawLine(startPoint.x(),startPoint.y()+cursorPixmap.height()/2+1,startPoint.x()+cursorPixmap.width(),startPoint.y()+cursorPixmap.height()/2+1);
        painter.drawLine(startPoint.x()+cursorPixmap.width()/2+1,startPoint.y(),startPoint.x()+cursorPixmap.width()/2+1,startPoint.y()+cursorPixmap.height());
    }
    update();
    //显示按钮与标签
    if(this->height()<m_endPos.y()+30){
        buttonSave->move(rect.x()+rect.width()-buttonSave->width()-10,rect.y()+rect.height()-30);
        buttonCancel->move(rect.x()+rect.width()-buttonSave->width()-buttonCancel->width()-8,rect.y()+rect.height()-30);
    }
    else{
        buttonSave->move(rect.x()+rect.width()-buttonSave->width()-10,rect.y()+rect.height());
        buttonCancel->move(rect.x()+rect.width()-buttonSave->width()-buttonCancel->width()-8,rect.y()+rect.height());
    }
    lblHeightWidth->setVisible(true);
    lblHeightWidth->move(rect.x(),rect.y()-12);
    lblHeightWidth->setText(QString::number(rect.width())+"x"+QString::number(rect.height()));
}

void ScreenShotWidget::on_buttonSave_Clicked()
{
    //清除笔刷,创建一个矩形区域
    close();
    QThread::msleep(30);
    QRect rect = QRect(m_startPos, m_endPos);
    //获取存储路径
    QDateTime currentDate=QDateTime::currentDateTime();
    QString mCURDIr = QCoreApplication::applicationDirPath();
    QString filePath=mCURDIr + "/screenshot/"+currentDate.toString("MMdd_hhmmss")+".bmp";
    QDir dir;
    if(!dir.exists(mCURDIr + "/screenshot")) dir.mkdir(mCURDIr + "/screenshot");
    //获取矩形区域截图(减去笔刷),存储在pixmap中
    QScreen *screen=QGuiApplication::primaryScreen();
    QPixmap pixmap=screen->grabWindow(QApplication::desktop()->winId(),rect.x(),rect.y(),rect.width(),rect.height());
    if (!pixmap.save(filePath)) QMessageBox::warning(this, tr("提示"), tr("保存图片失败"));
}

void ScreenShotWidget::on_buttonCancel_Clicked()
{
    //关闭透明页面
    close();
}

QPoint ScreenShotWidget::getPointInWhichSqure(QPoint point)
{
    int distance=8;
    if(abs(point.x()-m_topLeft.x())+abs(point.y()-m_topLeft.y())<distance) return m_topLeft;
    else if(abs(point.x()-m_topRight.x())+abs(point.y()-m_topRight.y())<distance) return m_topRight;
    else if(abs(point.x()-m_bottomLeft.x())+abs(point.y()-m_bottomLeft.y())<distance) return m_bottomLeft;
    else if(abs(point.x()-m_bottomRight.x())+abs(point.y()-m_bottomRight.y())<distance) return m_bottomRight;
    else if(abs(point.x()-m_topCenter.x())+abs(point.y()-m_topCenter.y())<distance) return m_topCenter;
    else if(abs(point.x()-m_bottomCenter.x())+abs(point.y()-m_bottomCenter.y())<distance) return m_bottomCenter;
    else if(abs(point.x()-m_leftCenter.x())+abs(point.y()-m_leftCenter.y())<distance) return m_leftCenter;
    else if(abs(point.x()-m_rightCenter.x())+abs(point.y()-m_rightCenter.y())<distance) return m_rightCenter;
    else return QPoint(-1,-1);
}

  • 10
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值