如何制作小部件的屏幕截图并将其粘贴到 QGraphicsView 中?

How to make a screenshot of the widget and paste it into the QGraphicsView?

我在表单上有 2 个 QGraphicsView 和一个 QWebEngineView 小部件,我需要 *(单击按钮 1)* 制作此 [=12= 中内容的屏幕截图] 与原始 QWebEngineView 边界有一些定义的挫折并将该屏幕截图保存为图像,同时将其作为对象并将该对象粘贴到第一个 QGraphicsView 和 *(点击button2)* insert saved image into the second QGraphicsView.

编辑: (我想制作 QtWebEngineWidgets 内部区域的屏幕截图并将该区域保留为一个对象。第二个问题我需要知道如何以两种不同的方式将这个区域粘贴到 QGraphicsView 中:(来自文件)并将其显示为一个对象而不保存。2 QGraphicsView 仅用于研究目的,它可能只是一个 QGraphicsView 并且通过点击 button1 屏幕截图正在制作并作为对象粘贴到 QGraphicsView 并通过点击 button2 - 屏幕截图正在制作(保存作为 png 并加载到 QGraphicsView))

这是我的代码:

import sys, os
from PyQt5.QtCore    import Qt
from PyQt5.QtGui     import QBrush, QPen, QScreen, QPixmap
from PyQt5.QtWidgets import QApplication, QStyleFactory, QMainWindow, QWidget, QVBoxLayout, QLabel
from PyQt5.QtWidgets import QGraphicsScene, QGraphicsView, QGraphicsItem, QPushButton
from pyqtgraph.Qt    import QtCore, QtGui
from PyQt5.QtWebEngineWidgets import QWebEngineView
from PyQt5.QtWidgets import QApplication, QDialog

class Geometry(QGraphicsView):
    def __init__(self):
        QGraphicsView.__init__(self)


class CentralPanel(QWidget):
    def __init__(self):
        QWidget.__init__(self)
        self.lblCoords = QLabel('MAP SELECTOR (object image):  ')
        self.lblCoords2 = QLabel('MAP SELECTOR (loaded from file image):  ')
        self.gvwShapes = Geometry()
        self.gvwShapes2 = Geometry()
        
        vbxDsply = QVBoxLayout()
        vbxDsply.addWidget(self.lblCoords)      # Capture coordinates of drawn line at window 1
        vbxDsply.addWidget(self.gvwShapes)      # add QGraphicsView #1
        
        vbxDsply.addWidget(self.lblCoords2)     # Capture coordinates of drawn line at window 2
        vbxDsply.addWidget(self.gvwShapes2)     # add QGraphicsView #2
        
        self.webEngineView = QWebEngineView()   # Add Google maps web window
        self.webEngineView.load(QtCore.QUrl("https://www.google.com/maps/@36.797966,-97.1413048,3464a,35y,0.92h/data=!3m1!1e3"))
        vbxDsply.addWidget(self.webEngineView)
        
        self.Button1 = QPushButton('Do screenshot of webEngineView save it and paste it into QGraphicsView2', self) # Button to load image to graphics view
        vbxDsply.addWidget(self.Button1)
        self.Button1.clicked.connect(self.button_screenshot)
        
        self.Button2 = QPushButton('Do screenshot of webEngineView and paste it into QGraphicsView1 ', self)
        vbxDsply.addWidget(self.Button2)
        self.Button2.clicked.connect(self.button_load_image)
        
        self.setLayout(vbxDsply)
        
        self.filename = "image.jpg"

    def button_screenshot(self):
        print('Screenshot is taken and saved as an image, Image loaded and inserted into the gvwShapes QGraphicsView1 ')
        app = QApplication(sys.argv)
        QScreen.grabWindow(app.primaryScreen(), QApplication.desktop().winId()).save(self.filename, 'png')

    def button_load_image(self):
        print('Screenshot is taken and inserted into the gvwShapes2 QGraphicsView2')
        
        # pix = QPixmap()
        # pix.load(self.filename)
        # pix = QPixmap(self.filename)
        # item = QGraphicsPixmapItem(pix)
        
        # scene = QGraphicsScence(self)
        # scene.addItem(item)
        # self.graphicsView.setScene(scene)
        
        scene = QtWidgets.QGraphicsScene(self)
        pixmap = QPixmap(self.filename)
        item = QtWidgets.QGraphicsPixmapItem(pixmap)
        scene.addItem(item)
        self.gvwShapes.setScene(scene)
        
        
        # scene = self.gvwShapes
        # self.image = QtGui.QPixmap(self.filename)
        # self.gvwShapes.add
        # scene.addItem(QtGui.QGraphicsPixmapItem(self.image))
        # self.view = self.QGraphicsView 
        # self.view.setScene(self.image)
        # self.view.show()
        
        
class MainWindow(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)
        self.setGeometry(200, 50, 700, 900) 
        self.setWindowTitle('MAP Selector REV01')
        self.setStyle(QStyleFactory.create('Cleanlooks'))
        self.CenterPane = CentralPanel()
        self.setCentralWidget(self.CenterPane)




# Catching exceptions and running a main loop
#
import traceback
def except_hook(exc_type, exc_value, exc_tb):
    tb = "".join(traceback.format_exception(exc_type, exc_value, exc_tb))
    print("error cached")
    print("error message:\n", tb)

if __name__ == "__main__":
    MainEventThred = QApplication([])
    os.environ["QTWEBENGINE_CHROMIUM_FLAGS"] = "--enable-logging --log-level=3"
    sys.excepthook = except_hook
    MainApp = MainWindow()
    MainApp.show()
    MainEventThred.exec()

为您的 QGraphicsView 设置场景。

self.gvwShapes = Geometry()
self.gvwShapes2 = Geometry()
self.gvwShapes.setScene(QGraphicsScene())
self.gvwShapes2.setScene(QGraphicsScene())

使用QWidget.grab()将其渲染成QPixmap并QGraphicsScene.addPixmap()将其添加到场景中。您可以使用 QRect 指定区域。

def button_screenshot(self):
    pixmap = self.webEngineView.grab(QRect(180, 100, 300, 280))
    pixmap.save(self.filename)
    self.gvwShapes2.scene().addPixmap(pixmap)

def button_load_image(self):
    self.gvwShapes.scene().addPixmap(QPixmap(self.filename))

在 QWebEngineView 中裁剪图像

如果你想实现QWebEngineView屏幕截图的裁剪,那么你必须使用QWebEngineView的focusProxy()上的QRubberBand(它是呈现网页并接收鼠标事件的小部件显示视图后创建)

from functools import cached_property
import sys

from PyQt5.QtCore import pyqtSignal, QEvent, QObject, QPoint, QRect, QSize, QUrl
from PyQt5.QtGui import QPixmap
from PyQt5.QtWidgets import QApplication, QLabel, QRubberBand
from PyQt5.QtWebEngineWidgets import QWebEngineView


class RubberBandManager(QObject):
    pixmap_changed = pyqtSignal(QPixmap, name="pixmapChanged")

    def __init__(self, widget):
        super().__init__(widget)
        self._origin = QPoint()
        self._widget = widget

        self.widget.installEventFilter(self)

    @property
    def widget(self):
        return self._widget

    @cached_property
    def rubberband(self):
        return QRubberBand(QRubberBand.Rectangle, self.widget)

    def eventFilter(self, source, event):
        if self.widget is source:
            if event.type() == QEvent.MouseButtonPress:
                self._origin = event.pos()
                self.rubberband.setGeometry(QRect(self._origin, QSize()))
                self.rubberband.show()
            elif event.type() == QEvent.MouseMove:
                self.rubberband.setGeometry(
                    QRect(self._origin, event.pos()).normalized()
                )
            elif event.type() == QEvent.MouseButtonRelease:
                rect = self.rubberband.geometry()
                pixmap = self.widget.grab(rect)
                self.pixmap_changed.emit(pixmap)
                self.rubberband.hide()
        return super().eventFilter(source, event)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    view = QWebEngineView()
    view.load(
        QUrl(
            "https://www.google.com/maps/@36.797966,-97.1413048,3464a,35y,0.92h/data=!3m1!1e3"
        )
    )
    view.show()
    rubberband_manager = RubberBandManager(view.focusProxy())

    label = QLabel()
    label.hide()

    def on_pixmap_changed(pixmap):
        label.setPixmap(pixmap)
        label.adjustSize()
        label.show()

    rubberband_manager.pixmap_changed.connect(on_pixmap_changed)

    ret = app.exec()
    sys.exit(ret)

在 QGraphicsView 中显示图像

要显示图像,您必须在加载 QPixmap 的地方使用 QGraphicsPixmapItem。

import sys

from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPixmap, QPainter, QPalette
from PyQt5.QtWidgets import (
    QApplication,
    QGraphicsView,
    QGraphicsScene,
    QGraphicsPixmapItem,
)


class ImageViewer(QGraphicsView):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform)
        self.setAlignment(Qt.AlignCenter)
        self.setBackgroundRole(QPalette.Dark)

        scene = QGraphicsScene()
        self.setScene(scene)

        self._pixmap_item = QGraphicsPixmapItem()
        scene.addItem(self._pixmap_item)

    def load_pixmap(self, pixmap):
        self._pixmap_item.setPixmap(pixmap)
        self.fitToWindow()

    def fitToWindow(self):
        self.fitInView(self.sceneRect(), Qt.KeepAspectRatio)

    def resizeEvent(self, event):
        super().resizeEvent(event)
        self.fitToWindow()


if __name__ == "__main__":
    app = QApplication(sys.argv)

    view = ImageViewer()
    view.resize(640, 480)
    view.show()

    pixmap = QPixmap("image.jpg")
    view.load_pixmap(pixmap)

    ret = app.exec()
    sys.exit(ret)

前面的小部件用于从文件加载图像:pixmap = QPixmap("/path/of/image") 或使用 RubberBandManager 的 pixmap_changed 信号提供的 QPixmap。