Qt實現截圖保存功能

1.實現結果

截圖樣子如下圖所示,顯示座標和大小,同時能夠保存截圖到本地文件,或者用於應用程序;可以拖拽調整大小,或者移動位置等功能;

2.實現方法

截圖界面頭文件

#ifndef SCREENWIDGET_H
#define SCREENWIDGET_H

#include <QWidget>
#include <QMenu>
#include <QPoint>
#include <QSize>
#include <QMouseEvent>
#include "CutPicToolBar.h"
enum  LOCATION 
{ 
    LEFT,
    RIGHT,
    UP, 
    DOWN,
    MIDLE,
    OUTRANGE,
    LEFTUP,
    LEFTDOWN,
    RIGHTUP,
    RIGHTDOWN
};

//截屏對象類
class Screen
{
public:
    enum STATUS { SELECT, MOV, SET_W_H, RESIZE };
    Screen() {}
    Screen(QSize size);

    void setStart(QPoint pos);
    void setEnd(QPoint pos);
    QPoint getStart();
    QPoint getEnd();

    QPoint getLeftUp();
    QPoint getRightDown();

    STATUS getStatus();
    void setStatus(STATUS status);

    int width();
    int height();
    bool isInArea(QPoint pos);          // 檢測pos是否在截圖區域內
    void move(QPoint p);                // 按 p 移動截圖區域
    LOCATION GetLocation(QPoint pos);
private:
    QPoint leftUpPos, rightDownPos;     //記錄 截圖區域 左上角、右下角
    QPoint startPos, endPos;            //記錄 鼠標開始位置、結束位置
    int maxWidth, maxHeight;            //記錄屏幕大小
    STATUS status;                      //三個狀態: 選擇區域、移動區域、設置width height

    void cmpPoint(QPoint &s, QPoint &e);//比較兩位置,判斷左上角、右下角
};

//截屏窗口類
class ScreenWidget : public QWidget
{
    Q_OBJECT
public:
    static ScreenWidget *Instance();
    explicit ScreenWidget(QWidget *parent = 0);
    CutPicToolBar m_CutPicToolBar;
signals:
    void signalCutPic(QString type,QString para );
private:
    static QScopedPointer<ScreenWidget> self;
    QMenu *menu;            //右鍵菜單對象
    Screen *screen;         //截屏對象
    QPixmap *fullScreen;    //保存全屏圖像
    QPixmap *bgScreen;      //模糊背景圖
    QPoint movPos;          //座標
    QString m_defaultPicDPath;
    bool m_bMousePressed = false;
    bool m_hasRect = false;
    LOCATION m_lo=OUTRANGE;
protected:
    void contextMenuEvent(QContextMenuEvent *e);
    void mousePressEvent(QMouseEvent *e);
    void mouseMoveEvent(QMouseEvent *e);
    void mouseReleaseEvent(QMouseEvent *e);
    void paintEvent(QPaintEvent *e);
    void showEvent(QShowEvent *e);
    void keyPressEvent(QKeyEvent *event);
    
    private slots:
    void saveScreenOther();
};
#endif // SCREENWIDGET_H

 

截圖界面cpp文件

#include "screenwidget.h"
#include <QMutex>
#include <QApplication>
#include <QPainter>
#include <QDesktopWidget>
#include <QFileDialog>
#include <QEvent>
#include <QDateTime>
#include <QStringList>
#include <QRect>
#pragma execution_character_set("utf-8")
#if (QT_VERSION > QT_VERSION_CHECK(5,0,0))
#include <QScreen>
#endif

#define STRDATETIME qPrintable (QDateTime::currentDateTime().toString("yyyyMMddHHmmss"))

Screen::Screen(QSize size)
{
    maxWidth = size.width();
    maxHeight = size.height();

    startPos = QPoint(-1, -1);
    endPos = startPos;
    leftUpPos = startPos;
    rightDownPos = startPos;
    status = SELECT;
}

int Screen::width()
{
    return maxWidth;
}

int Screen::height()
{
    return maxHeight;
}

Screen::STATUS Screen::getStatus()
{
    return status;
}

void Screen::setStatus(STATUS status)
{
    this->status = status;
}

void Screen::setEnd(QPoint pos)
{
    endPos = pos;
    leftUpPos = startPos;
    rightDownPos = endPos;
    cmpPoint(leftUpPos, rightDownPos);
}

void Screen::setStart(QPoint pos)
{
    startPos = pos;
}

QPoint Screen::getEnd()
{
    return endPos;
}

QPoint Screen::getStart()
{
    return startPos;
}

QPoint Screen::getLeftUp()
{
    return leftUpPos;
}

QPoint Screen::getRightDown()
{
    return rightDownPos;
}

bool Screen::isInArea(QPoint pos)
{
    if (pos.x() > leftUpPos.x() && pos.x() < rightDownPos.x() && pos.y() > leftUpPos.y() && pos.y() < rightDownPos.y()) {
        return true;
    }

    return false;
}
LOCATION Screen::GetLocation(QPoint pos)
{
    LOCATION location= LOCATION::OUTRANGE;
    QRect Left, right, up, down, leftup, leftdown, rightup, rightdown, midle;
    int cornelw = 3;
    int width = rightDownPos.x() - leftUpPos.x();
    int height= rightDownPos.y() - leftUpPos.y();
    Left = QRect(leftUpPos.x() - cornelw, leftUpPos.y() + cornelw, 2 * cornelw, height-2 * cornelw);
    leftup = QRect(leftUpPos.x()-cornelw, leftUpPos.y()- cornelw,2* cornelw,2*cornelw);
    leftdown = QRect(leftUpPos.x() - cornelw, rightDownPos.y() - cornelw, 2 * cornelw, 2 * cornelw);
    right= QRect(rightDownPos.x() - cornelw, leftUpPos.y() + cornelw, 2 * cornelw, height-2 * cornelw);
    rightup= QRect(rightDownPos.x() - cornelw, leftUpPos.y() - cornelw, 2 * cornelw,  2 * cornelw);
    rightdown = QRect(rightDownPos.x() - cornelw, rightDownPos.y() - cornelw, 2 * cornelw, 2 * cornelw);
    up= QRect(leftUpPos.x() + cornelw, leftUpPos.y() - cornelw, width-2 * cornelw, 2 * cornelw);
    down= QRect(leftUpPos.x() + cornelw, rightDownPos.y() - cornelw, width- 2 * cornelw, 2 * cornelw);
    midle= QRect(leftUpPos.x() + cornelw, leftUpPos.y() + cornelw, width-2 * cornelw, height - 2 * cornelw);
    if (leftdown.contains(pos))
    {
        location = LOCATION::LEFTDOWN;
    }
    if (Left.contains(pos))
    {
        location = LOCATION::LEFT;
    }
    if (leftup.contains(pos))
    {
        location = LOCATION::LEFTUP;
    }
    if (right.contains(pos))
    {
        location = LOCATION::RIGHT;
    }
    if (rightup.contains(pos))
    {
        location = LOCATION::RIGHTUP;
    }
    if (rightdown.contains(pos))
    {
        location = LOCATION::RIGHTDOWN;
    }
    if (down.contains(pos))
    {
        location = LOCATION::DOWN;
    }
    if (up.contains(pos))
    {
        location = LOCATION::UP;
    }
    if (midle.contains(pos))
    {
        location = LOCATION::MIDLE;
    }
    return location;
}
void Screen::move(QPoint p)
{
    int lx = leftUpPos.x() + p.x();
    int ly = leftUpPos.y() + p.y();
    int rx = rightDownPos.x() + p.x();
    int ry = rightDownPos.y() + p.y();

    if (lx < 0) {
        lx = 0;
        rx -= p.x();
    }

    if (ly < 0) {
        ly = 0;
        ry -= p.y();
    }

    if (rx > maxWidth) {
        rx = maxWidth;
        lx -= p.x();
    }

    if (ry > maxHeight) {
        ry = maxHeight;
        ly -= p.y();
    }

    leftUpPos = QPoint(lx, ly);
    rightDownPos = QPoint(rx, ry);
    startPos = leftUpPos;
    endPos = rightDownPos;
}

void Screen::cmpPoint(QPoint &leftTop, QPoint &rightDown)
{
    QPoint l = leftTop;
    QPoint r = rightDown;

    if (l.x() <= r.x()) {
        if (l.y() <= r.y()) {
            ;
        }
        else {
            leftTop.setY(r.y());
            rightDown.setY(l.y());
        }
    }
    else {
        if (l.y() < r.y()) {
            leftTop.setX(r.x());
            rightDown.setX(l.x());
        }
        else {
            QPoint tmp;
            tmp = leftTop;
            leftTop = rightDown;
            rightDown = tmp;
        }
    }
}

QScopedPointer<ScreenWidget> ScreenWidget::self;
ScreenWidget *ScreenWidget::Instance()
{
    if (self.isNull()) {
        static QMutex mutex;
        QMutexLocker locker(&mutex);
        if (self.isNull()) {
            self.reset(new ScreenWidget);
        }
    }

    return self.data();
}

ScreenWidget::ScreenWidget(QWidget *parent) : QWidget(parent)
{
    //menu = new QMenu(this);
    //QAction *serachface = new QAction(tr("截圖搜索"), this);
    //QAction *quit = new QAction(tr("退出"), this);
    //connect(serachface, SIGNAL(triggered()), this, SLOT(saveScreen()));
    //connect(quit, SIGNAL(triggered()), this, SLOT(hide()));  //直接觸發窗口的close函數
    ///* 添加菜單項 */
    //menu->addAction(serachface);
    //menu->addAction(quit);
    //
    //取得屏幕大小
    screen = new Screen(QApplication::desktop()->size());
    //保存全屏圖像
    fullScreen = new QPixmap();
    m_CutPicToolBar.setParent(this);
    m_CutPicToolBar.hide();
    connect(m_CutPicToolBar.ui.pBSaveTo, &QPushButton::clicked, this, &ScreenWidget::saveScreenOther);
    connect(m_CutPicToolBar.ui.pBClose, &QPushButton::clicked, this, [=]() {
        hide();
        m_CutPicToolBar.hide();
        m_hasRect = false;
    });
    connect(m_CutPicToolBar.ui.pBSearchFace, &QPushButton::clicked, this, [=]() {
        int x = screen->getLeftUp().x();
        int y = screen->getLeftUp().y();
        int w = screen->getRightDown().x() - x;
        int h = screen->getRightDown().y() - y;
        QString strPath = qApp->applicationDirPath();
        strPath = strPath + "/CutPic/";
        QDir dir(strPath);
        if (!dir.exists())
        {
            dir.mkpath(strPath);
        }
        QString fileName = QString("%1screen_%2.png").arg(strPath).arg(STRDATETIME);
        fullScreen->copy(x, y, w, h).save(fileName, "png");
        hide();
        m_CutPicToolBar.hide();
        m_hasRect = false;
        emit signalCutPic("SearchFace", fileName);
    });
    setMouseTracking(true);
}

void ScreenWidget::paintEvent(QPaintEvent *)
{
    int x = screen->getLeftUp().x();
    int y = screen->getLeftUp().y();
    int w = screen->getRightDown().x() - x;
    int h = screen->getRightDown().y() - y;

    QPainter painter(this);

    QPen pen;
    pen.setColor(QColor(116, 255, 126));
    pen.setWidth(2);
    pen.setStyle(Qt::SolidLine);
    painter.setPen(pen);
    painter.drawPixmap(0, 0, *bgScreen);

    if (w != 0 && h != 0) {
        painter.drawPixmap(x, y, fullScreen->copy(x, y, w, h));
    }
    painter.drawRect(x, y, w, h);
    //繪製四個邊角
    QBrush brush;   //畫刷。填充幾何圖形的調色板,由顏色和填充風格組成
    int cwidth = 4;
    brush.setColor(QColor(116, 255, 126));
    brush.setStyle(Qt::SolidPattern);
    painter.setBrush(brush);
    painter.drawRect(x, y, cwidth, cwidth);
    painter.drawRect(x + w - cwidth, y, cwidth, cwidth);
    painter.drawRect(x, y + h - cwidth, cwidth, cwidth);
    painter.drawRect(x + w - cwidth, y + h - cwidth, cwidth, cwidth);
    
    pen.setColor(Qt::yellow);
    painter.setPen(pen);
    painter.drawText(x + 2, y - 8, tr("截圖座標:(%1,%2)-圖片大小:(%3,%4)").arg(x).arg(y).arg(w).arg(h));
    //painter.drawText(x + 2, y - 8, tr("圖片大小:( %1 x %2 )").arg(w).arg(h));
    
}

void ScreenWidget::showEvent(QShowEvent *)
{
    QPoint point(-1, -1);
    screen->setStart(point);
    screen->setEnd(point);

#if (QT_VERSION <= QT_VERSION_CHECK(5,0,0))
    *fullScreen = fullScreen->grabWindow(QApplication::desktop()->winId(), 0, 0, screen->width(), screen->height());
#else
    QScreen *pscreen = QApplication::primaryScreen();
    *fullScreen = pscreen->grabWindow(QApplication::desktop()->winId(), 0, 0, screen->width(), screen->height());
#endif

    //設置透明度實現模糊背景
    QPixmap pix(screen->width(), screen->height());
    pix.fill((QColor(0, 0, 0, 125)));
    bgScreen = new QPixmap(*fullScreen);
    QPainter p(bgScreen);
    p.drawPixmap(0, 0, pix);
    m_CutPicToolBar.hide();
    m_hasRect = false;
}

void ScreenWidget::keyPressEvent(QKeyEvent *event)
{
    if (event->key() == Qt::Key_Escape)
    {
        hide();
        m_CutPicToolBar.hide();
        m_hasRect = false;
    }
}
void ScreenWidget::saveScreenOther()
{
    QString name = QString("%1.png").arg(STRDATETIME);
    if (m_defaultPicDPath.length()!=0)
    {
        if (m_defaultPicDPath.right(1)!="/")
        {
            name ="/" + name;
        }
        name = m_defaultPicDPath + name;
    }
    QString fileName = QFileDialog::getSaveFileName(this, "保存圖片", name, "png Files (*.png)");
    if (fileName!="")
    {
        if (!fileName.endsWith(".png")) {
            fileName += ".png";
        }
        QFileInfo info(fileName);
        m_defaultPicDPath = info.absolutePath();
        if (fileName.length() > 0) {
            int x = screen->getLeftUp().x();
            int y = screen->getLeftUp().y();
            int w = screen->getRightDown().x() - x;
            int h = screen->getRightDown().y() - y;
            fullScreen->copy(x, y, w, h).save(fileName, "png");
        }
    }
    hide();
    m_CutPicToolBar.hide();
    m_hasRect = false;
}
void ScreenWidget::mouseMoveEvent(QMouseEvent *e)
{
    if (m_bMousePressed == true)
    {
        if (screen->getStatus() == Screen::SELECT)
        {
            screen->setEnd(e->pos());
            m_hasRect = true;
        }
        else if (screen->getStatus() == Screen::MOV)
        {
            QPoint p(e->x() - movPos.x(), e->y() - movPos.y());
            screen->move(p);
            movPos = e->pos();
        }
        else if (screen->getStatus() == Screen::RESIZE)
        {
            
            QPoint point,pointright;
            switch (m_lo)
            {
            case LEFT:
                point = screen->getLeftUp();
                point.setX(e->pos().x());
                screen->setStart(point);
                screen->setEnd(screen->getRightDown());
                break;
            case RIGHT:
                point = screen->getRightDown();
                point.setX(e->pos().x());
                screen->setEnd(point);
                break;
            case UP:
                point = screen->getLeftUp();
                point.setY(e->pos().y());
                screen->setStart(point);
                screen->setEnd(screen->getRightDown());
                break;
            case DOWN:
                point = screen->getRightDown();
                point.setY(e->pos().y());
                screen->setEnd(point);
                break;
            case MIDLE:
                break;
            case OUTRANGE:
                break;
            case LEFTUP:
                point = e->pos();
                screen->setStart(point);
                screen->setEnd(screen->getRightDown());
                break;
            case LEFTDOWN:
                point = screen->getLeftUp();
                pointright = screen->getRightDown();
                point.setX(e->pos().x());
                pointright.setY(e->pos().y());
                screen->setStart(point);
                screen->setEnd(pointright);
                break;
            case RIGHTUP:
                point = screen->getLeftUp();
                pointright = screen->getRightDown();
                point.setY(e->pos().y());
                pointright.setX(e->pos().x());
                screen->setStart(point);
                screen->setEnd(pointright);
                break;
            case RIGHTDOWN:
                point = e->pos();
                screen->setEnd(point);
                break;
            default:
                break;
            }
        }
    }
    LOCATION lo = screen->GetLocation(e->pos());
    switch (lo)
    {
    case LEFT:
        setCursor(Qt::SizeHorCursor);
        break;
    case RIGHT:
        setCursor(Qt::SizeHorCursor);
        break;
    case UP:
        setCursor(Qt::SizeVerCursor);
        break;
    case DOWN:
        setCursor(Qt::SizeVerCursor);
        break;
    case MIDLE:
        setCursor(Qt::SizeAllCursor);
        break;
    case OUTRANGE:
        setCursor(Qt::ArrowCursor);
        break;
    case LEFTUP:
        setCursor(Qt::SizeFDiagCursor);
        break;
    case LEFTDOWN:
        setCursor(Qt::SizeBDiagCursor);
        break;
    case RIGHTUP:
        setCursor(Qt::SizeBDiagCursor);
        break;
    case RIGHTDOWN:
        setCursor(Qt::SizeFDiagCursor);
        break;
    default:
        setCursor(Qt::ArrowCursor);
        break;
    }
    this->repaint();
}

void ScreenWidget::mousePressEvent(QMouseEvent *e)
{
    m_bMousePressed = true;
    m_CutPicToolBar.hide();
    if (m_hasRect)
    {
        LOCATION lo = screen->GetLocation(e->pos());
        if (lo==LOCATION::OUTRANGE)
        {
            screen->setStart(e->pos());
            screen->setStatus(Screen::SELECT);
        }
        else if (lo==LOCATION::MIDLE)
        {
            screen->setStatus(Screen::MOV);
            movPos = e->pos();//QPoint(screen->getLeftUp().x() - e->pos().x(), screen->getLeftUp().y() - e->pos().y());
        }
        else
        {
            m_lo = lo;
            screen->setStatus(Screen::RESIZE);
        }
    }
    else
    {
        screen->setStatus(Screen::SELECT);
        m_hasRect = false;
        screen->setStart(e->pos());
    }
    this->update();
}

void ScreenWidget::mouseReleaseEvent(QMouseEvent *)
{
    m_bMousePressed = false;
    if (screen->getStatus() == Screen::SELECT) 
    {
        screen->setStatus(Screen::MOV);
    }
    else if (screen->getStatus() == Screen::MOV) 
    {
        this->setCursor(Qt::ArrowCursor);
    }
    int x = screen->getRightDown().x()+2;
    int y = screen->getLeftUp().y();
    m_CutPicToolBar.move(x, y);
    m_CutPicToolBar.show();
}

void ScreenWidget::contextMenuEvent(QContextMenuEvent *)
{
    /*this->setCursor(Qt::ArrowCursor);
    menu->exec(cursor().pos());*/
}

然後再需求截圖的地方直接調用showFullScreen函數,就可以拖動鼠標進行截圖了;

connect(ui.pBCutPic, &QPushButton::clicked, this, [=]() {
        ScreenWidget::Instance()->showFullScreen();
    });

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章