Программа обрезки экрана - прозрачная область обрезки - PullRequest
2 голосов
/ 26 мая 2020

Я в процессе преобразования моей успешной программы снятия экрана с Tkinter на PYQT5. Мой вопрос в том, как создать полностью прозрачную область обрезки (было бы неплохо динамически обновлять квадратную область). Снаружи квадрат будет полупрозрачным. Я просмотрел переполнение стека и inte rnet и не смог найти примера этого (другие не являются полностью прозрачным окном для рисования). Я приложил свой код и иллюстрацию того, что я ищу. "SnippingWidget" - это класс, который выполняет обрезку c.

enter image description here enter image description here

import sys

from PyQt5 import QtCore, QtGui
from PyQt5.QtWidgets import QMainWindow, QApplication, QAction, QWidget
from PyQt5.QtGui import QIcon, QKeySequence
from PIL import ImageGrab

class App(QMainWindow):
    def __init__(self):
        super().__init__()

        self.initUI()
        self.topMenu()

    def initUI(self):

        self.setWindowTitle('Lil Snippy')
        self.setWindowIcon(QIcon('assets/lilSnippyIcon.png'))
        self.setGeometry(400, 300, 400, 300)
        self.show()

    def topMenu(self):
        menubar = self.menuBar()

        fileMenu = menubar.addMenu('File')
        saveAct = QAction(QIcon('assets/saveIcon.png'), 'Save', self)
        saveAsAct = QAction(QIcon('assets/saveAsIcon.png'), 'Save As', self)


        modeMenu = menubar.addMenu('Mode')
        snipAct = QAction(QIcon('assets/cameraIcon.png'), 'Snip', self)
        snipAct.setShortcut(QKeySequence('F1'))
        snipAct.triggered.connect(self.activateSnipping)
        videoAct = QAction(QIcon('assets/videoIcon.png'), 'Video', self)
        videoAct.setShortcut('F2')
        soundAct = QAction(QIcon('assets/audioIcon.png'), 'Sound', self)
        soundAct.setShortcut('F3')
        autoAct = QAction(QIcon('assets/automationIcon.png'), 'Automation', self)
        autoAct.setShortcut('F4')

        helpMenu = menubar.addMenu('Help')
        helpAct = QAction(QIcon('assets/helpIcon.png'), 'Help', self)
        aboutAct = QAction(QIcon('assets/aboutIcon.png'), 'About', self)

        fileMenu.addAction(saveAct)
        fileMenu.addAction(saveAsAct)
        modeMenu.addAction(snipAct)
        modeMenu.addAction(videoAct)
        modeMenu.addAction(soundAct)
        modeMenu.addAction(autoAct)
        helpMenu.addAction(helpAct)
        helpMenu.addAction(aboutAct)

    def activateSnipping(self):
        print("yes")
        self.Snipper = SnippingWidget()
        application.hide()

class SnippingWidget(QMainWindow):
    def __init__(self, parent = None):
        super(SnippingWidget, self).__init__(parent)
        self.setStyleSheet("background-color: transparent;")
        self.setWindowOpacity(.2)
        self.showFullScreen()

        self.outsideSquareColor = 'red'
        self.squareThickness = 4

        self.startX = None
        self.startY = None
        self.endX = None
        self.endY = None
        self.begin = QtCore.QPoint()
        self.end = QtCore.QPoint()

    def mousePressEvent(self, event):
        self.begin = event.pos()
        self.end = self.begin
        self.startX = event.x()
        self.startY = event.y()
        self.update()

    def mouseReleaseEvent(self, QMouseEvent):
        self.destroy()
        x1 = min(self.begin.x(), self.end.x())
        y1 = min(self.begin.y(), self.end.y())
        x2 = max(self.begin.x(), self.end.x())
        y2 = max(self.begin.y(), self.end.y())
        img = ImageGrab.grab(bbox=(x1, y1, x2, y2))

        img.save('snips/testImage.png')
        application.show()

    def mouseMoveEvent(self, event):
        self.end = event.pos()
        self.update()

    def paintEvent(self, event):
        qp = QtGui.QPainter(self)
        qp.setPen(QtGui.QPen(QtGui.QColor('red'), self.squareThickness))
        trans = QtGui.QColor(255,255,255,255)
        qp.setBrush(trans)
        rect = QtCore.QRectF(self.begin, self.end)
        qp.drawRect(rect)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    application = App()
    sys.exit(app.exec_())

1 Ответ

2 голосов
/ 26 мая 2020

Вы должны использовать QPainterPath, чтобы вычесть прямоугольник из окна с выбранным прямоугольником:

import sys

from PyQt5 import QtCore, QtGui, QtWidgets

from PIL import ImageGrab


class App(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()

        self.initUI()
        self.topMenu()

    def initUI(self):
        self.setWindowTitle("Lil Snippy")
        self.setWindowIcon(QtGui.QIcon("assets/lilSnippyIcon.png"))
        self.setGeometry(400, 300, 400, 300)

    def topMenu(self):
        menubar = self.menuBar()

        fileMenu = menubar.addMenu("File")
        saveAct = QtWidgets.QAction(QtGui.QIcon("assets/saveIcon.png"), "Save", self)
        saveAsAct = QtWidgets.QAction(
            QtGui.QIcon("assets/saveAsIcon.png"), "Save As", self
        )

        modeMenu = menubar.addMenu("Mode")
        snipAct = QtWidgets.QAction(QtGui.QIcon("assets/cameraIcon.png"), "Snip", self)
        snipAct.setShortcut(QtGui.QKeySequence("F1"))
        snipAct.triggered.connect(self.activateSnipping)
        videoAct = QtWidgets.QAction(QtGui.QIcon("assets/videoIcon.png"), "Video", self)
        videoAct.setShortcut("F2")
        soundAct = QtWidgets.QAction(QtGui.QIcon("assets/audioIcon.png"), "Sound", self)
        soundAct.setShortcut("F3")
        autoAct = QtWidgets.QAction(
            QtGui.QIcon("assets/automationIcon.png"), "Automation", self
        )
        autoAct.setShortcut("F4")

        helpMenu = menubar.addMenu("Help")
        helpAct = QtWidgets.QAction(QtGui.QIcon("assets/helpIcon.png"), "Help", self)
        aboutAct = QtWidgets.QAction(QtGui.QIcon("assets/aboutIcon.png"), "About", self)

        fileMenu.addAction(saveAct)
        fileMenu.addAction(saveAsAct)
        modeMenu.addAction(snipAct)
        modeMenu.addAction(videoAct)
        modeMenu.addAction(soundAct)
        modeMenu.addAction(autoAct)
        helpMenu.addAction(helpAct)
        helpMenu.addAction(aboutAct)

        self.snipper = SnippingWidget()
        self.snipper.closed.connect(self.on_closed)

    def activateSnipping(self):
        self.snipper.showFullScreen()
        self.hide()

    def on_closed(self):
        self.snipper.hide()
        self.show()


class SnippingWidget(QtWidgets.QMainWindow):
    closed = QtCore.pyqtSignal()

    def __init__(self, parent=None):
        super(SnippingWidget, self).__init__(parent)
        self.setStyleSheet("background-color: transparent;")
        self.setWindowOpacity(0.2)

        self.outsideSquareColor = "red"
        self.squareThickness = 4

        self.start_point = QtCore.QPoint()
        self.end_point = QtCore.QPoint()

    def mousePressEvent(self, event):
        self.start_point = event.pos()
        self.end_point = event.pos()
        self.update()

    def mouseMoveEvent(self, event):
        self.end_point = event.pos()
        self.update()

    def mouseReleaseEvent(self, QMouseEvent):
        r = QtCore.QRect(self.start_point, self.end_point).normalized()
        img = ImageGrab.grab(bbox=r.getCoords())
        img.save("snips/testImage.png")
        self.closed.emit()

    def paintEvent(self, event):
        qp = QtGui.QPainter(self)
        qp.setPen(
            QtGui.QPen(QtGui.QColor(self.outsideSquareColor), self.squareThickness)
        )
        trans = QtGui.QColor(255, 255, 255, 255)
        qp.setBrush(trans)

        outer = QtGui.QPainterPath()
        outer.addRect(QtCore.QRectF(self.rect()))

        inner = QtGui.QPainterPath()
        inner.addRect(QtCore.QRectF(self.start_point, self.end_point).normalized())
        r = outer - inner
        qp.drawPath(r)


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    application = App()
    application.show()
    sys.exit(app.exec_())

Обновление:

class SnippingWidget(QtWidgets.QMainWindow):
    closed = QtCore.pyqtSignal()

    def __init__(self, parent=None):
        super(SnippingWidget, self).__init__(parent)
        self.setAttribute(QtCore.Qt.WA_NoSystemBackground, True)
        self.setAttribute(QtCore.Qt.WA_TranslucentBackground, True)
        self.setStyleSheet("background:transparent;")
        self.setWindowFlags(QtCore.Qt.FramelessWindowHint)

        self.outsideSquareColor = "red"
        self.squareThickness = 4

        self.start_point = QtCore.QPoint()
        self.end_point = QtCore.QPoint()

    def mousePressEvent(self, event):
        self.start_point = event.pos()
        self.end_point = event.pos()
        self.update()

    def mouseMoveEvent(self, event):
        self.end_point = event.pos()
        self.update()

    def mouseReleaseEvent(self, QMouseEvent):
        r = QtCore.QRect(self.start_point, self.end_point).normalized()
        img = ImageGrab.grab(bbox=r.getCoords())
        img.save("snips/testImage.png")
        self.closed.emit()

    def paintEvent(self, event):
        trans = QtGui.QColor(255, 255, 255)
        r = QtCore.QRectF(self.start_point, self.end_point).normalized()

        qp = QtGui.QPainter(self)
        trans.setAlphaF(0.2)
        qp.setBrush(trans)
        outer = QtGui.QPainterPath()
        outer.addRect(QtCore.QRectF(self.rect()))
        inner = QtGui.QPainterPath()
        inner.addRect(r)
        r_path = outer - inner
        qp.drawPath(r_path)

        qp.setPen(
            QtGui.QPen(QtGui.QColor(self.outsideSquareColor), self.squareThickness)
        )
        trans.setAlphaF(0)
        qp.setBrush(trans)
        qp.drawRect(r)
...