• Post author:
  • Post category:python
  • Post comments:3评论

使用 PyQt5 实现截图功能,功能点:
• 选框截图:鼠标左键选择区域双击截屏,右击重新截图。
• 全屏截图:不选区域,直接鼠标双击截全屏。

# Author: cp

import sys, time, logging
from PyQt5.QtCore import Qt, QRect
from PyQt5.QtGui import QPen, QPainter, QColor, QGuiApplication
from PyQt5.QtWidgets import QApplication, QWidget, QFileDialog

class Screenshot(QWidget):
    """截图"""

    # 初始化变量
    fullScreenImage = None
    captureImage = None
    isMousePressLeft = None
    beginPosition = None
    endPosition = None

    # 创建 QPainter 对象
    painter = QPainter()

    def __init__(self):
        super().__init__()
        self.initWindow()             # 初始化窗口
        self.captureFullScreen()      # 捕获全屏

    def initWindow(self):
        """初始化窗口"""
        self.setCursor(Qt.CrossCursor)               # 设置光标
        self.setWindowFlag(Qt.FramelessWindowHint)   # 产生无边框窗口,用户不能通过窗口系统移动或调整无边界窗口的大小
        self.setWindowState(Qt.WindowFullScreen)     # 窗口全屏无边框

    def captureFullScreen(self):
        """捕获全屏"""
        # 捕获当前屏幕,返回像素图
        self.fullScreenImage = QGuiApplication.primaryScreen().grabWindow(QApplication.desktop().winId())

    def mousePressEvent(self, event):
        """鼠标按下事件"""
        # 如果鼠标事件为左键,则记录起始鼠标光标相对于窗口的位置
        if event.button() == Qt.LeftButton:
            self.beginPosition = event.pos()
            self.isMousePressLeft = True
        # 如果鼠标事件为右键,如果已经截图了则重新开始截图,如果没有截图就退出
        if event.button() == Qt.RightButton:
            if self.captureImage is not None:
                self.captureImage = None
                self.update()    # 更新,会擦除之前的选框
            else:
                self.close()

    def mouseMoveEvent(self, event):
        """鼠标移动事件"""
        if self.isMousePressLeft is True:
            self.endPosition = event.pos()
            self.update()

    def mouseReleaseEvent(self, event):
        """鼠标释放事件"""
        self.endPosition = event.pos()
        self.isMousePressLeft = False

    def mouseDoubleClickEvent(self, event):
        """鼠标双击事件"""
        self.saveImage()
        self.close()

    def paintBackgroundImage(self):
        """绘制背景图"""
        # 填充颜色,黑色半透明
        fillColor = QColor(0, 0, 0, 100)
        # 加载显示捕获的图片到窗口
        self.painter.drawPixmap(0, 0, self.fullScreenImage)
        # 填充颜色到给定的矩形
        self.painter.fillRect(self.fullScreenImage.rect(), fillColor)

    def getRectangle(self, beginPoint, endPoint):
        """获取矩形选框"""
        # 计算矩形宽和高
        rectWidth = int(abs(beginPoint.x() - endPoint.x()))
        rectHeight = int(abs(beginPoint.y() - endPoint.y()))
        # 计算矩形左上角 x 和 y
        rectTopleftX = beginPoint.x() if beginPoint.x() < endPoint.x() else endPoint.x()
        rectTopleftY = beginPoint.y() if beginPoint.y() < endPoint.y() else endPoint.y()
        # 构造一个以(x,y)为左上角,给定宽度和高度的矩形
        pickRect = QRect(rectTopleftX, rectTopleftY, rectWidth, rectHeight)
        # 调试日志
        # logging.info('开始坐标:%s,%s', beginPoint.x(), beginPoint.y())
        # logging.info('结束坐标:%s,%s', endPoint.x(), endPoint.y())
        return pickRect

    def paintSelectBox(self):
        """绘制选框"""
        # 画笔颜色,蓝色
        penColor = QColor(30, 150, 255)  # 画笔颜色
        # 设置画笔属性,蓝色、2px大小、实线
        self.painter.setPen(QPen(penColor, 2, Qt.SolidLine))
        if self.isMousePressLeft is True:
            pickRect = self.getRectangle(self.beginPosition, self.endPosition)  # 获得要截图的矩形框
            self.captureImage = self.fullScreenImage.copy(pickRect)             # 捕获截图矩形框内的图片
            self.painter.drawPixmap(pickRect.topLeft(), self.captureImage)      # 填充截图的图片
            self.painter.drawRect(pickRect)     # 绘制矩形边框

    def paintEvent(self,event):
        """接收绘制事件开始绘制"""
        self.painter.begin(self)        # 开始绘制
        self.paintBackgroundImage()     # 绘制背景
        self.paintSelectBox()           # 绘制选框
        self.painter.end()              # 结束绘制

    def saveImage(self):
        """保存图片"""
        # 获取用户选择的文件名的完整路径
        fileName = QFileDialog.getSaveFileName(self, '保存图片', time.strftime("%Y%m%d%H%M%S"), ".png")
        # 保存用户选择的文件。如果选取了区域,就保存区域图片;如果没有选取区域,就保存全屏图片
        if self.captureImage is not None:
            self.captureImage.save(fileName[0] + fileName[1])
        else:
            self.fullScreenImage.save(fileName[0] + fileName[1])

    def keyPressEvent(self, event):
        """按键事件"""
        # 如果按下 ESC 键,则退出截图
        if event.key() == Qt.Key_Escape:
            self.close()
        # 如果按下 Enter 键,并且已经选取了区域,就截图选区图片
        if event.key() == Qt.Key_Enter or event.key() == Qt.Key_Return:
            if self.captureImage is not None:
                self.saveImage()
                self.close()

if __name__ == '__main__':
    # 调试日志
    # logger = logging.getLogger()
    # logger.setLevel(logging.DEBUG)
    # sh = logging.StreamHandler()
    # formatter = logging.Formatter('%(message)s')
    # sh.setFormatter(formatter)
    # logger.addHandler(sh)

    app = QApplication(sys.argv)    # 创建 QApplication 对象
    windows = Screenshot()          # 创建 Screenshot 对象
    windows.show()                  # 显示窗口
    sys.exit(app.exec_())           # 进入主事件循环并等待直到 exit() 被调用

这篇文章有 3 个评论

  1. Avatar photo
    匿名

    怎么给它加按钮启动啊 另外显示图像像素大小和坐标

    1. Avatar photo
      cp

      简单点,再创建个继承 QWidget 类的窗口类,加个按钮,点击事件调用 Screenshot 类就行了,至于图像像素大小和坐标自己去扩展功能呗

  2. Avatar photo
    Magic

    感謝大神分享!!!

发表回复

验证码: + 22 = 27