Создание полноэкранной программы рисования с прозрачным фоном моего приложения - PullRequest
7 голосов
/ 29 сентября 2019

Моя цель - создать небольшую программу для ПК / Windows, которая позволит мне буквально рисовать поверх моего экрана и сохранять результат в виде png с прозрачным фоном. Как программное обеспечение, как Epic Pen или gInk но мой путь. Все с использованием Python 3.7 и PyQt5.

До сих пор мне удалось получить функциональное приложение для рисования (в основном, следуя этому уроку ), потому что я изучаю PyQt одновременно. Мне удалось сохранить свои черновики в виде png с прозрачным фоном. Я могу сделать чертежную доску полноэкранной и без полей.

Теперь проблема в том, что я не могу найти способ сделать весь фон прозрачным. Хотя я нашел способы сделать окно прозрачным и без полей, используя эти:

Window = Window()
Window.setStyleSheet("background:transparent;")
Window.setAttribute(Qt.WA_TranslucentBackground)
Window.setWindowFlags(Qt.FramelessWindowHint)
Window.show()

И это работает ... Пока у меня нет области рисования. Я могу нарисовать его, он сохранится на прозрачном фоне, но он будет отображаться черным цветом.

Так что я ищу это решение. Даже без PyQt мне все равно, если я могу заставить мою программу работать.

Итак, вот что у меня есть (я покажу вам окно с рамкой, чтобы было легче объяснить): enter image description here

А вот что я хочу: enter image description here

А вот мой код:

import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QMenuBar, QMenu, QAction, QShortcut, QFileDialog
from PyQt5.QtGui import QIcon, QImage, QPainter, QPen
from PyQt5.QtCore import Qt, QPoint


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

        top = 400
        left = 400
        width = 800
        height = 600

        icon = "icons/icon.png"

        self.setWindowTitle("ScreenPen drawing board")
        self.setGeometry(top, left, width, height)
        self.setWindowIcon(QIcon(icon))

# ---------- sets image ----------
        self.image = QImage(self.size(), QImage.Format_RGBA64)
        self.image.fill(Qt.transparent)

# ---------- init drawing state ----------
        self.drawing = False
        self.brushSize = 2
        self.brushColor = Qt.red
        self.lastPoint = QPoint()

# ---------- Define Menus ----------
    # mainmenu
        mainMenu = self.menuBar()
        fileMenu = mainMenu.addMenu("File")
        toolMenu = mainMenu.addMenu("Tool")
        toolColor = mainMenu.addMenu("Color")
    # smenu save
        saveAction = QAction(QIcon("icons/save.png"), "Save", self)
        saveAction.setShortcut("Ctrl+S")
        fileMenu.addAction(saveAction)
        saveAction.triggered.connect(self.saveFrame)
    # smenu clear frame
        clearFrameAction = QAction(QIcon("icons/clear.png"), "Clear Frame", self)
        clearFrameAction.setShortcut("Ctrl+Del")
        fileMenu.addAction(clearFrameAction)
        clearFrameAction.triggered.connect(self.clearFrame)
    # smenu Tool Pen
        toolPenAction = QAction(QIcon("icons/toolPen.png"), "Pen", self)
        # clearAction.setShortcut("Ctrl+Del")
        toolMenu.addAction(toolPenAction)

# ---------- Catch Mouse Down --------

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.drawing = True
            self.lastPoint = event.pos()

# ---------- Catch Mouse Move --------
    def mouseMoveEvent(self, event):
        if (event.buttons() & Qt.LeftButton) & self.drawing:
            painter = QPainter(self.image)
            painter.setPen(QPen(self.brushColor, self.brushSize, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))
            painter.drawLine(self.lastPoint, event.pos())
            self.lastPoint = event.pos()
            self.update()

# ---------- Catch Mouse Up --------
    def mouseReleaseEvent(self, event):
        if event.button == Qt.LeftButton:
            self.drawing = False

# ---------- Paint --------
    def paintEvent(self, event):
        canvasPainter = QPainter(self)
        canvasPainter.drawImage(self.rect(), self.image, self.image.rect())

# ---------- Save Action ----------
    def saveFrame(self):
        filePath,  _ = QFileDialog.getSaveFileName(self, "Save Image", "", "PNG(*.png);;JPEG(*.jpg *.jpeg);; ALL Files(*.*)")
        if filePath == "":
            return
        self.image.save(filePath)

# ---------- Clear Frame Action ----------
    def clearFrame(self):
        self.image.fill(Qt.white)
        self.update()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    Window = Window()
    # Window style
    Window.setStyleSheet("background:transparent;")
    Window.setAttribute(Qt.WA_TranslucentBackground)
    # Window.setWindowFlags(Qt.FramelessWindowHint)
    Window.show()
    app.exec()

Ответы [ 2 ]

3 голосов
/ 06 октября 2019

Один из способов сделать это (который должен работать на большинстве платформ) - создать изображение всего рабочего стола, которое затем обрезается до области, закрытой вашим окном. Это можно сделать довольно легко в Qt, используя QScreen.grabWindow :

def saveFrame(self):
    filePath,  _ = QFileDialog.getSaveFileName(self, "Save Image", "", "PNG(*.png);;JPEG(*.jpg *.jpeg);; ALL Files(*.*)")
    if filePath == "":
        return

    screen = QApplication.desktop().windowHandle().screen()
    wid = QApplication.desktop().winId()
    pixmap = screen.grabWindow(wid, self.x(), self.y(), self.width(), self.height())
    pixmap.save(filePath)

Или, возможно:

    screen = self.windowHandle().screen()
    pixmap = screen.grabWindow(0, self.x(), self.y(), self.width(), self.height())
    pixmap.save(filePath)

Они оба работают для меня в Linux, но яне проверял их на других платформах. Если вы также хотите получить оконную раму, используйте self.frameGeometry(), чтобы получить необходимые размеры.

0 голосов
/ 03 октября 2019

Я не уверен, возможно ли это. В качестве обходного пути вы можете сделать снимок экрана соответствующей области с python и использовать его в качестве фона. Вам, конечно, придется обновить снимок экрана, если вы переместите окно.

Сделайте снимок экрана с python для Windows: Получить снимок экрана для Windows с Python?

...