QT截图程序,可多屏幕截图二,增加调整截图区域功能

QT截图程序,可多屏幕截图二,增加调整截图区域功能

码农世界 2024-05-31 前端 90 次浏览 0个评论

上一篇QT截图程序,可多屏幕截图只是实现了最基本的截图功能,虽然能用但是缺点也有,没办法更改选中的区域,这在实际使用时不太方便。这篇增加了这个功能。先看看效果。

实现代码为:

头文件

#ifndef MASKWIDGET_H
#define MASKWIDGET_H
#include 
#include "mainwindow.h"
namespace Ui {
class MaskWidget;
}
enum SnapState{
    NoSnap,
    Snapped,
    PreLeftDrag,
    LeftDrag,
    PreRightDrag,
    RightDrag,
    PreTopDrag,
    TopDrag,
    PreBottomDrag,
    BottomDrag
};
class MaskWidget : public QWidget
{
    Q_OBJECT
public:
    explicit MaskWidget(QWidget *parent = nullptr);
    ~MaskWidget();
protected:
    void mousePressEvent(QMouseEvent *event)override;
    void mouseReleaseEvent(QMouseEvent *event)override;
    void mouseMoveEvent(QMouseEvent *event)override;
    void paintEvent(QPaintEvent *event)override;
    void keyPressEvent(QKeyEvent *event) override;
    void showEvent(QShowEvent *event) override;
private slots:
    void ResetSnap();
private:
    QPoint m_pressPos;
    QPoint m_newPos;
    QRect m_maskRect{0, 0, 0, 0};
    QPixmap m_image;
    bool isPressed{false};
    MainWindow m;
    SnapState snapstate{NoSnap};
private:
    Ui::MaskWidget *ui;
};
#endif // MASKWIDGET_H

源文件

#include "maskwidget.h"
#include "ui_maskwidget.h"
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
const int MINSIZE = 10;
MaskWidget::MaskWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::MaskWidget)
{
    ui->setupUi(this);
    setMouseTracking(true);
    setWindowFlags(Qt::FramelessWindowHint);
    setWindowOpacity(0.8);
    QList screens = QGuiApplication::screens();
    int width = 0;
    int height = 0;
    for (QScreen *screen : screens)
    {
        width += screen->geometry().width();
        if (height < screen->geometry().height())
        {
            height = screen->geometry().height();
        }
        qDebug()<geometry();
    }
    this->setFixedSize(width, height);
    m.hide();
    connect(&m, SIGNAL(resetSnap()), this, SLOT(ResetSnap()));
}
MaskWidget::~MaskWidget()
{
    delete ui;
}
void MaskWidget::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton)
    {
        if (m_maskRect.width() == 0 && m_maskRect.width() == 0)
        {
            m_pressPos = event->pos();
            this->setCursor(Qt::CrossCursor);
            isPressed = true;
            update();
        }
        if (snapstate == PreLeftDrag)
        {
            snapstate = LeftDrag;
        }
        else if (snapstate == PreRightDrag)
        {
            snapstate = RightDrag;
        }
        else if (snapstate == PreTopDrag)
        {
            snapstate = TopDrag;
        }
        else if (snapstate == PreBottomDrag)
        {
            snapstate = BottomDrag;
        }
    }
    if (event->button() == Qt::RightButton)
    {
        if (m_maskRect.width() > 0)
        {
            isPressed = false;
            QRegion all(0, 0, width(), height());
        QRegion sub(m_maskRect);
        setMask(all.subtracted(sub));
        QPixmap combined(this->width(), this->height());
        combined.fill(Qt::transparent);
        QPainter painter(&combined);
        QList screens = QGuiApplication::screens();
        for (QScreen *screen : screens)
        {
            m_image = screen->grabWindow(0);
            painter.drawPixmap(screen->geometry().x(), 0, screen->geometry().width(), screen->geometry().height(), m_image);
        }
//            auto gpos = mapToGlobal(event->pos());
//            auto gposStart = mapToGlobal(m_pressPos);
//            qDebug()<hide();
        m.SetImage(m_image);
        update();
        m.show();
        }
    }
    QWidget::mousePressEvent(event);
}
void MaskWidget::mouseReleaseEvent(QMouseEvent *event)
{
    qDebug()<<__func__<<" "<setCursor(Qt::ArrowCursor);
    }
    switch(snapstate)
    {
    case LeftDrag:
    {
        snapstate = Snapped;
        this->setCursor(Qt::ArrowCursor);
    }
        break;
    case RightDrag:
    {
        snapstate = Snapped;
        this->setCursor(Qt::ArrowCursor);
    }
        break;
    case TopDrag:
    {
        snapstate = Snapped;
        this->setCursor(Qt::ArrowCursor);
    }
        break;
    case BottomDrag:
    {
        snapstate = Snapped;
        this->setCursor(Qt::ArrowCursor);
    }
        break;
    default:
        break;
    }
    return QWidget::mouseReleaseEvent(event);
}
void MaskWidget::mouseMoveEvent(QMouseEvent* event)
{
    if (isPressed)
    {
        m_newPos = event->pos();
        QRegion all(0, 0, width(), height());
        m_maskRect = QRect(qMin(m_pressPos.x(), m_newPos.x()),
                       qMin(m_pressPos.y(), m_newPos.y()),
                       qAbs(m_newPos.x() - m_pressPos.x()),
                       qAbs(m_newPos.y() - m_pressPos.y()));
        QRegion sub(m_maskRect);
        setMask(all.subtracted(sub));
        
        update();
    }
    else
    {
        switch(snapstate)
        {
        case Snapped:
        {
            if (m_maskRect.bottom() > event->pos().y() && m_maskRect.top() < event->pos().y())
            {
                if (qFabs(m_maskRect.left() - event->pos().x()) < 5)
                {
                    this->setCursor(Qt::SizeHorCursor);
                    this->snapstate = PreLeftDrag;
                }
                else if (qFabs(m_maskRect.right() - event->pos().x()) < 5)
                {
                    this->setCursor(Qt::SizeHorCursor);
                    this->snapstate = PreRightDrag;
                }
            }
            else if (m_maskRect.left() < event->pos().x() && m_maskRect.right() > event->pos().y())
            {
                if (qFabs(m_maskRect.top() - event->pos().y()) < 5)
                {
                    this->setCursor(Qt::SizeVerCursor);
                    this->snapstate = PreTopDrag;
                }
                else if (qFabs(m_maskRect.bottom() - event->pos().y()) < 5)
                {
                    this->setCursor(Qt::SizeVerCursor);
                    this->snapstate = PreBottomDrag;
                }
            }
        }
            break;
        case LeftDrag:
        {
            if (event->pos().x() + MINSIZE >= m_maskRect.right())
            {
                m_maskRect.setLeft(m_maskRect.right() - MINSIZE);
            }
            else
            {
                m_maskRect.setLeft(event->pos().x() + 2);
            }
            QRegion sub(m_maskRect);
            QRegion all(0, 0, width(), height());
            setMask(all.subtracted(sub));
            qDebug()<pos().x()) >= 5 || event->pos().y() > m_maskRect.bottom() || event->pos().y() < m_maskRect.top())
            {
                this->setCursor(Qt::ArrowCursor);
                this->snapstate = Snapped;
            }
        }
            break;
        case PreRightDrag:
        {
            if (qFabs(event->pos().x() - m_maskRect.right()) >= 5 || event->pos().y() > m_maskRect.bottom() || event->pos().y() < m_maskRect.top())
            {
                this->setCursor(Qt::ArrowCursor);
                this->snapstate = Snapped;
            }
        }
            break;
        case RightDrag:
        {
            if (event->pos().x() - MINSIZE <= m_maskRect.left())
            {
                m_maskRect.setRight(m_maskRect.left() + MINSIZE);
            }
            else
            {
                m_maskRect.setRight(event->pos().x() - 2);
            }
            QRegion sub(m_maskRect);
            QRegion all(0, 0, width(), height());
            setMask(all.subtracted(sub));
            qDebug()<pos().y() - m_maskRect.top()) >= 5 || event->pos().x() < m_maskRect.left() || event->pos().x() > m_maskRect.right())
            {
                this->setCursor(Qt::ArrowCursor);
                this->snapstate = Snapped;
            }
        }
            break;
        case TopDrag:
        {
            if (event->pos().y() + MINSIZE >= m_maskRect.bottom())
            {
                m_maskRect.setTop(m_maskRect.bottom() - MINSIZE);
            }
            else
            {
                m_maskRect.setTop(event->pos().y() + 2);
            }
            QRegion sub(m_maskRect);
            QRegion all(0, 0, width(), height());
            setMask(all.subtracted(sub));
            update();
        }
            break;
        case PreBottomDrag:
        {
            if (qFabs(event->pos().y() - m_maskRect.bottom()) >= 5 || event->pos().x() < m_maskRect.left() || event->pos().x() > m_maskRect.right())
            {
                this->setCursor(Qt::ArrowCursor);
                this->snapstate = Snapped;
            }
        }
            break;
        case BottomDrag:
        {
            if (event->pos().y() - MINSIZE <= m_maskRect.top())
            {
                m_maskRect.setBottom(m_maskRect.top() + MINSIZE);
            }
            else
            {
                m_maskRect.setBottom(event->pos().y() - 2);
            }
            QRegion sub(m_maskRect);
            QRegion all(0, 0, width(), height());
            setMask(all.subtracted(sub));
            update();
        }
            break;
        default:
            break;
        }
    }
    return QWidget::mouseMoveEvent(event);
}
void MaskWidget::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    
    painter.setPen(Qt::red);
    painter.drawRect(m_maskRect.x()-1, m_maskRect.y()-1, m_maskRect.width()+1, m_maskRect.height() + 1);
}
void MaskWidget::keyPressEvent(QKeyEvent *event)
{
    if (event->key() == Qt::Key_Escape)
    {
        close();
    }
    else if (event->key() == Qt::Key_Enter)
    {
        if (isPressed)
        {
            isPressed = false;
            snapstate = Snapped;
            this->setCursor(Qt::ArrowCursor);
        }
    }
    QWidget::keyPressEvent(event);
}
void MaskWidget::showEvent(QShowEvent *event)
{
    QWidget::showEvent(event);
}
void MaskWidget::ResetSnap()
{
    QRegion all(0, 0, width(), height());
    setMask(all);
    m_maskRect.setRect(0,0,0,0);
    snapstate = NoSnap;
    this->show();
}

思路:

第一,要保留住选中的框,选中后停留下来不自动跳转。实现方式为在mouseRelease函数里面不再进行隐藏和跳转,跳转改称点击鼠标右键。

第二,当鼠标移动到边框附近时,鼠标的形状要进行变化,表示可以拖动了。左右边对应的是双向横箭头,上下边对应的是双向竖箭头。这里取值距离5作为触发区域,当距离小于5时可进行拖动。类似途中的红色区域。

第三,为了配合形状变化,用一个枚举来表示不同的状态。

enum SnapState{
    NoSnap,
    Snapped,
    PreLeftDrag,
    LeftDrag,
    PreRightDrag,
    RightDrag,
    PreTopDrag,
    TopDrag,
    PreBottomDrag,
    BottomDrag
};

NoSnap表示初始状态,没有开始截图的时候。

Snapped表示已经截图了,此时会显示一个矩形方框。

PreLeftDrag表示进入左侧边框可拖动状态,此时鼠标形状变化成左右箭头。

        PreLeftDrag----按下鼠标左键--->LeftDrag(可移动鼠标来拖动边框)

        PreLeftDrag----鼠标距离左边框的距离大于5--->Snapped(鼠标状态恢复正常)

LeftDrag表示进入可拖动状态,可拖动鼠标更改左边框位置。此时松开鼠标则回到PreLeftDrag状态

其他几个状态类似。

根据鼠标的位置和动作,变化不同的状态。这里由于逻辑简单,没有使用状态机。

为了有更好的显示效果,这里限制了拖动区域,不会出现一条边覆盖另一条的情况,可在动图里看出来。

这样修改后,截图工具好用了很多。

转载请注明来自码农世界,本文标题:《QT截图程序,可多屏幕截图二,增加调整截图区域功能》

百度分享代码,如果开启HTTPS请参考李洋个人博客
每一天,每一秒,你所做的决定都会改变你的人生!

发表评论

快捷回复:

评论列表 (暂无评论,90人围观)参与讨论

还没有评论,来说两句吧...

Top