如何制作小部件的屏幕截图并将其粘贴到 QGraphicsView 中?
Posted
技术标签:
【中文标题】如何制作小部件的屏幕截图并将其粘贴到 QGraphicsView 中?【英文标题】:How to make a screenshot of the widget and paste it into the QGraphicsView? 【发布时间】:2021-05-03 02:41:26 【问题描述】:我在表单上有 2 个QGraphicsView
和一个QWebEngineView
小部件,我需要*(单击按钮1)* 制作此QWebEngineView
中内容的屏幕截图,与原始内容相比有一些明确的挫折QWebEngineView
边框并将屏幕截图另存为图像,同时将其保留为对象并将此对象粘贴到第一个QGraphicsView
和*(单击按钮2)*将保存的图像插入第二个@987654328 @。
编辑: (我想对 QtWebEngineWidgets 内的区域进行屏幕截图并将该区域保留为对象。第二个问题我需要知道如何以两种不同的方式将该区域粘贴到 QGraphicsView 中:(来自文件)并将其显示为对象而不保存。2 QGraphicsView 仅用于学习目的,它可能只是一个 QGraphicsView 并且通过点击 button1 屏幕截图正在制作并作为对象粘贴到 QGraphicsView 并通过点击 button2 -screenshot 正在制作(保存作为 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的目的是什么,你目前的问题是什么? @eyllanesc 问题是:我不知道如何截取 QtWebEngineWidgets 内的区域并将该区域保留为对象。第二个问题我需要知道如何以两种不同的方式将该区域粘贴到 QGraphicsView 中:(从文件中)并将其显示为对象而不保存。 2 QGraphicsView 仅用于学习目的,它可能只是一个 QGraphicsView 并通过点击 button1 屏幕截图并将其作为对象粘贴到 QGraphicsView 并点击 button2 -screenshot 正在制作(保存为 png 并加载到 QGraphicsView) 我只需要了解这些操作的机制 如果您在帖子中指出这一点会很好,因为该要求不明确 【参考方案1】:在 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。
【讨论】:
谢谢,但由于某种原因,我对装饰器有一些问题:ImportError: cannot import name 'cached_property' from 'functools'。试图找出问题所在。 @NickPV 你用的是什么版本的python?我的代码适用于 python 3.8 或更高版本 哦,我明白了,这可能是个问题,我的所有项目都使用 3.7.4 @NickPV 然后安装 backports.cached-property:python -m pip install backports.cached-property
并将 from functools import cached_property
更改为 from backports.cached_property import cached_property
。如果您未指明您使用的工具的版本,则假定您使用的是最新版本。
它真的很酷,很好的例子。但是对于谷歌地图,它与从谷歌地图本身移动的地图重叠,当你选择区域时,鼠标正在将该区域与主要谷歌地图一起移动,并且有点目标移动【参考方案2】:
为你的 QGraphicsViews 设置一个场景。
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))
【讨论】:
是的,这看起来正是我所需要的。唯一的问题是如何裁剪屏幕截图的中心(或定义挫折)? @NickPVgrab()
如果您不想抓取整个小部件,则接受 QRect 参数。 (从 QtCore 导入 QRect)。以上是关于如何制作小部件的屏幕截图并将其粘贴到 QGraphicsView 中?的主要内容,如果未能解决你的问题,请参考以下文章