pyqt5 实现屏幕截屏

最近发现很多时间都浪费在解决以前很久解决过却忘了具体怎么解决的事情上,遂决定也开始在博客上做好记录,也希望能帮助同样咸鱼的屌丝码农,一起copy & paste。。。

先上0注释的一坨shit:

class KxScreenshotDelegate:
    def finishedWithData(self, data):
        pass

class KxScreenshotStatus:
    init = 0
    dragging = 1
    ok = 2
    drafting = 3

class KxScreenshotWidget(QWidget):
    def __init__(self, img, delegate):
        super(KxScreenshotWidget, self).__init__()
        self.startX = 0
        self.staryY = 0
        self.endX = 0
        self.endY = 0
        self.draftPointss = []
        self.img = img
        self.delegate = delegate
        self.status = KxScreenshotStatus.init
        self.setCursor(QtCore.Qt.CrossCursor)
        self.initUI()

    def initUI(self):
        self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
        self.setWindowTitle("screenshot")
        # self.setGeometry(0,0,screen.width(),screen.height())
        # self.setWindowOpacity(0.3)
        palette1 = QtGui.QPalette()
        palette1.setBrush(self.backgroundRole(), QtGui.QBrush(self.img))
        self.setPalette(palette1)
        tipLabel = QLabel("截图模式,按ESC退出,按右键取消选框,按回车发送截图")
        tipLabel.setObjectName("tip")
        tipLabel.setStyleSheet(
            "QLabel#tip{background-color:white;padding:5px;color:black;font-weight:bold;font-size:16px;}")
        vBox = QVBoxLayout()
        tipBar = QHBoxLayout()
        tipBar.addStretch(1)
        tipBar.addWidget(tipLabel)
        tipBar.addStretch(1)
        vBox.addLayout(tipBar)
        vBox.addStretch(1)
        self.setLayout(vBox)
        mask = QWidget(self)
        black = QColor(0, 0, 0)
        black.setAlphaF(0.2)
        palette2 = QtGui.QPalette()
        palette2.setBrush(mask.backgroundRole(), black)
        mask.setPalette(palette2)
        mask.setAutoFillBackground(True)
        mask.setGeometry(0, 0, self.img.width(), self.img.height())

    def paintEvent(self, e):
        if self.status == KxScreenshotStatus.dragging or self.status == KxScreenshotStatus.ok or self.status == KxScreenshotStatus.drafting:
            qp = QPainter()
            qp.begin(self)
            self.drawCutRect(qp)
            if self.status == KxScreenshotStatus.ok or self.status == KxScreenshotStatus.drafting:
                self.drawDraft(qp)
            qp.end()

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Escape:
            self.close()
        elif event.key() == Qt.Key_Return or event.key() == Qt.Key_Enter:
            if self.status == KxScreenshotStatus.ok:
                ba = QByteArray()
                buf = QBuffer(ba)
                buf.open(QIODevice.WriteOnly)
                cuttedImg = self.img.copy(QRect(QPoint(self.startX, self.startY), QPoint(self.endX, self.endY)))
                painter = QPainter(cuttedImg)
                painter.begin(self)
                pen = QPen(Qt.red, 2, Qt.SolidLine)
                painter.setPen(pen)
                for points in self.draftPointss:
                    for i in range(len(points) - 1):
                        p0 = points[i]
                        p1 = points[i + 1]
                        painter.drawLine(p0.x() - self.startX, p0.y()-self.startY, p1.x()-self.startX, p1.y()-self.startY)
                painter.end()
                cuttedImg.save(buf,format="PNG")
                self.delegate.finishedWithData(ba.data())
                buf.close()
                self.close()

    def mouseMoveEvent(self, e):
        if self.status == KxScreenshotStatus.dragging:
            self.endX = e.x()
            self.endY = e.y()
            self.update()
        elif self.status == KxScreenshotStatus.drafting:
            if e.x() <  self.startX or e.x() > self.endX or e.y() < self.startY or e.y() > self.endY:
                if len(self.draftPointss[-1]) > 0:
                    self.draftPointss.append([])
            else:
                self.draftPointss[-1].append(QPoint(e.x(),e.y()))
            self.update()

    def mousePressEvent(self, e):
        if e.button() == Qt.LeftButton:
            if self.status == KxScreenshotStatus.init:
                self.startX = e.x()
                self.startY = e.y()
                self.status = KxScreenshotStatus.dragging
            elif self.status == KxScreenshotStatus.ok:
                self.status = KxScreenshotStatus.drafting
                self.draftPointss.append([])
        elif e.button() == Qt.RightButton:
            if self.status == KxScreenshotStatus.dragging:
                self.status = KxScreenshotStatus.init
                self.setCursor(QtCore.Qt.CrossCursor)
            elif self.status == KxScreenshotStatus.ok:
                if len(self.draftPointss) > 0:
                    self.draftPointss = []
                else:
                    self.status = KxScreenshotStatus.init
                    self.setCursor(QtCore.Qt.CrossCursor)
            elif self.status == KxScreenshotStatus.drafting:
                self.draftPointss = []
                self.status = KxScreenshotStatus.ok
        self.update()

    def mouseReleaseEvent(self, e):
        if e.button() == Qt.LeftButton:
            if self.status == KxScreenshotStatus.dragging:
                self.status = KxScreenshotStatus.ok
                self.setCursor(QtCore.Qt.UpArrowCursor)
                x0 = self.startX
                x1 = self.endX
                if self.startX > self.endX:
                    x0 = self.endX
                    x1 = self.startX
                y0 = self.startY
                y1 = self.endY
                if self.startY > self.endY:
                    y0 = self.endY
                    y1 = self.startY
                self.startX = x0
                self.startY = y0
                self.endX = x1
                self.endY = y1
            elif self.status == KxScreenshotStatus.drafting:
                self.status = KxScreenshotStatus.ok
        self.update()

    def drawCutRect(self, qp):
        pen = QPen(Qt.blue, 2, Qt.DashLine)
        qp.setPen(pen)
        r = QRect(QPoint(self.startX, self.startY), QPoint(self.endX, self.endY))
        qp.drawRect(r)

    def drawDraft(self,qp):
        pen = QPen(Qt.red, 2, Qt.SolidLine)
        qp.setPen(pen)
        for points in self.draftPointss:
            for i in range(len(points) -1):
                p0 = points[i]
                p1 = points[i+1]
                qp.drawLine(p0.x(),p0.y(),p1.x(),p1.y())

KxScreenshotWidget即是用户点击截屏后,跳出的那个覆盖整个屏幕的窗口。这个窗口的背景是一张图片,即用户点击截屏后的那张屏幕截图。

整个逻辑实现采用了状态机的思想,用户先截取窗口,然后可以在截取窗口上画红线。

接下来是如何调用:

class KxChatWidget(QWidget,KxScreenshotDelegate,KxEmotionWindowDelegate):
    ... #略去其余代码只保留调用截屏相关

    def toScreenshot(self):
        if self.session is None:
            return
        desktop = QDesktopWidget()
        r = desktop.screenGeometry(desktop.screenNumber(self))
        self.screenshot = KxScreenshotWidget( QGuiApplication.primaryScreen().grabWindow(0, r.x(), r.y(), r.width(), r.height()),self)
        self.screenshot.setGeometry(desktop.screenGeometry(desktop.screenNumber(self)))
        self.screenshot.show()

    def finishedWithData(self, data):
       #此处的data即为截屏后的结果,是个二进制数组,可直接展示

 

截图结果如下:


猜你喜欢

转载自blog.csdn.net/lucytheslayer/article/details/79723822