上一篇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状态
其他几个状态类似。
根据鼠标的位置和动作,变化不同的状态。这里由于逻辑简单,没有使用状态机。
为了有更好的显示效果,这里限制了拖动区域,不会出现一条边覆盖另一条的情况,可在动图里看出来。
这样修改后,截图工具好用了很多。
还没有评论,来说两句吧...