QPixmap & QRubberBand 缩放问题
QPixmap & QRubberBand scaling troubles
我有一个 "working" 示例,但有几个问题我似乎无法弄清楚。我计算了橡皮筋内的 topLeft 和 bottomRight 坐标,并将它们转换为小部件坐标。但是 pixmap.copy() 不会复制这些坐标。不断变化的全局和小部件坐标系令人困惑,所以我假设我没有正确理解坐标系。
import sys
from PyQt5.QtCore import Qt, QRect
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QRubberBand
from PyQt5.QtWidgets import QHBoxLayout, QSizeGrip
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(526, 478)
self.centralWidget = QtWidgets.QWidget(MainWindow)
self.centralWidget.setObjectName("centralWidget")
self.gridLayout = QtWidgets.QGridLayout(self.centralWidget)
self.gridLayout.setContentsMargins(11, 11, 11, 11)
self.gridLayout.setSpacing(6)
self.gridLayout.setObjectName("gridLayout")
self.label = QtWidgets.QLabel(self.centralWidget)
self.label.setText("")
self.label.setPixmap(QtGui.QPixmap("ava.jpg"))
self.label.setScaledContents(True)
self.label.setObjectName("label")
self.gridLayout.addWidget(self.label, 0, 0, 1, 1)
self.pushButton = QtWidgets.QPushButton(self.centralWidget)
self.pushButton.setObjectName("pushButton")
self.gridLayout.addWidget(self.pushButton, 1, 0, 1, 1)
MainWindow.setCentralWidget(self.centralWidget)
self.menuBar = QtWidgets.QMenuBar(MainWindow)
self.menuBar.setGeometry(QtCore.QRect(0, 0, 526, 25))
self.menuBar.setObjectName("menuBar")
MainWindow.setMenuBar(self.menuBar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "Resizeable QLabel Example"))
self.pushButton.setText(_translate("MainWindow", "Crop"))
class Test_Resize(QMainWindow, Ui_MainWindow):
def __init__(self):
super(Test_Resize, self).__init__()
self.setupUi(self)
self.show()
def run(self):
self.pushButton.clicked.connect(self.cropImage)
self.band = Resizable_rubber_band(self.label)
self.band.move(50, 50)
self.band.resize(200, 266)
self.band.setMinimumSize(30, 30)
def cropImage(self):
rect = self.band.getCoverage()
# copy(QRect( x, y, width, height))
self.label.setPixmap(self.label.pixmap().copy(rect))
self.label.repaint()
class Resizable_rubber_band(QWidget):
def __init__(self, parent=None):
super(Resizable_rubber_band, self).__init__(parent)
# tell QSizeGrip to resize this widget instead of top-level window
self.setWindowFlags(Qt.SubWindow)
self.layout = QHBoxLayout(self)
self.layout.setContentsMargins(0, 0, 0, 0)
self.grip1 = QSizeGrip(self)
self.grip2 = QSizeGrip(self)
self.layout.addWidget(self.grip1, 0, Qt.AlignLeft | Qt.AlignTop)
self.layout.addWidget(self.grip2, 0, Qt.AlignRight | Qt.AlignBottom)
self.rubberband = QRubberBand(QRubberBand.Rectangle, self)
self.rubberband.move(0, 0)
self.rubberband.show()
self.show()
def resizeEvent(self, event):
# force 4h x 3w aspect ratio using QSize
# if width < height: height = 1.333 * width
# if width > height: width = height / 1.333
# width = self.width()
# height = self.height()
# if(width < height):
# height = int(width * 1.333)
# else:
# width = int(height / 1.333)
# self.rubberband.resize(QSize(width, height))
self.rubberband.resize(self.size())
def getCoverage(self):
localCoords = self.contentsRect()
print("localCoords: ", localCoords)
TL = self.mapToGlobal(localCoords.topLeft())
BR = localCoords.bottomRight()
# TL+BR to get width & height
widgetCoords = QRect(TL, TL+BR)
print("widgetCoords: ", widgetCoords)
return widgetCoords
app = QApplication(sys.argv)
program = Test_Resize()
program.run()
sys.exit(app.exec_())
当您启用 scaledContents 属性:
self.label.setScaledContents(True)
QPixmap
的坐标与 QLabel
的像素不对应,例如假设 QPixmap
是 20 x 20 而 QLabel
20 x 10 然后它必须在像素图的高度从 20 到 10 进行转换。
首先要做的是用self.label.mapFromGlobal()
将全局坐标转换为QLabel
坐标,然后通过按初始变化比例缩放宽度和高度来变换矩形。
def cropImage(self):
rect = self.band.getCoverage()
r = QRect(self.label.mapFromGlobal(rect.topLeft()), rect.size())
px = self.label.pixmap()
tr = QtGui.QTransform()
tr.scale(px.size().width()*1.0/self.label.size().width(), px.size().height()*1.0/self.label.size().height())
r = tr.mapRect(r)
self.label.setPixmap(px.copy(r))
我有一个 "working" 示例,但有几个问题我似乎无法弄清楚。我计算了橡皮筋内的 topLeft 和 bottomRight 坐标,并将它们转换为小部件坐标。但是 pixmap.copy() 不会复制这些坐标。不断变化的全局和小部件坐标系令人困惑,所以我假设我没有正确理解坐标系。
import sys
from PyQt5.QtCore import Qt, QRect
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QRubberBand
from PyQt5.QtWidgets import QHBoxLayout, QSizeGrip
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(526, 478)
self.centralWidget = QtWidgets.QWidget(MainWindow)
self.centralWidget.setObjectName("centralWidget")
self.gridLayout = QtWidgets.QGridLayout(self.centralWidget)
self.gridLayout.setContentsMargins(11, 11, 11, 11)
self.gridLayout.setSpacing(6)
self.gridLayout.setObjectName("gridLayout")
self.label = QtWidgets.QLabel(self.centralWidget)
self.label.setText("")
self.label.setPixmap(QtGui.QPixmap("ava.jpg"))
self.label.setScaledContents(True)
self.label.setObjectName("label")
self.gridLayout.addWidget(self.label, 0, 0, 1, 1)
self.pushButton = QtWidgets.QPushButton(self.centralWidget)
self.pushButton.setObjectName("pushButton")
self.gridLayout.addWidget(self.pushButton, 1, 0, 1, 1)
MainWindow.setCentralWidget(self.centralWidget)
self.menuBar = QtWidgets.QMenuBar(MainWindow)
self.menuBar.setGeometry(QtCore.QRect(0, 0, 526, 25))
self.menuBar.setObjectName("menuBar")
MainWindow.setMenuBar(self.menuBar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "Resizeable QLabel Example"))
self.pushButton.setText(_translate("MainWindow", "Crop"))
class Test_Resize(QMainWindow, Ui_MainWindow):
def __init__(self):
super(Test_Resize, self).__init__()
self.setupUi(self)
self.show()
def run(self):
self.pushButton.clicked.connect(self.cropImage)
self.band = Resizable_rubber_band(self.label)
self.band.move(50, 50)
self.band.resize(200, 266)
self.band.setMinimumSize(30, 30)
def cropImage(self):
rect = self.band.getCoverage()
# copy(QRect( x, y, width, height))
self.label.setPixmap(self.label.pixmap().copy(rect))
self.label.repaint()
class Resizable_rubber_band(QWidget):
def __init__(self, parent=None):
super(Resizable_rubber_band, self).__init__(parent)
# tell QSizeGrip to resize this widget instead of top-level window
self.setWindowFlags(Qt.SubWindow)
self.layout = QHBoxLayout(self)
self.layout.setContentsMargins(0, 0, 0, 0)
self.grip1 = QSizeGrip(self)
self.grip2 = QSizeGrip(self)
self.layout.addWidget(self.grip1, 0, Qt.AlignLeft | Qt.AlignTop)
self.layout.addWidget(self.grip2, 0, Qt.AlignRight | Qt.AlignBottom)
self.rubberband = QRubberBand(QRubberBand.Rectangle, self)
self.rubberband.move(0, 0)
self.rubberband.show()
self.show()
def resizeEvent(self, event):
# force 4h x 3w aspect ratio using QSize
# if width < height: height = 1.333 * width
# if width > height: width = height / 1.333
# width = self.width()
# height = self.height()
# if(width < height):
# height = int(width * 1.333)
# else:
# width = int(height / 1.333)
# self.rubberband.resize(QSize(width, height))
self.rubberband.resize(self.size())
def getCoverage(self):
localCoords = self.contentsRect()
print("localCoords: ", localCoords)
TL = self.mapToGlobal(localCoords.topLeft())
BR = localCoords.bottomRight()
# TL+BR to get width & height
widgetCoords = QRect(TL, TL+BR)
print("widgetCoords: ", widgetCoords)
return widgetCoords
app = QApplication(sys.argv)
program = Test_Resize()
program.run()
sys.exit(app.exec_())
当您启用 scaledContents 属性:
self.label.setScaledContents(True)
QPixmap
的坐标与 QLabel
的像素不对应,例如假设 QPixmap
是 20 x 20 而 QLabel
20 x 10 然后它必须在像素图的高度从 20 到 10 进行转换。
首先要做的是用self.label.mapFromGlobal()
将全局坐标转换为QLabel
坐标,然后通过按初始变化比例缩放宽度和高度来变换矩形。
def cropImage(self):
rect = self.band.getCoverage()
r = QRect(self.label.mapFromGlobal(rect.topLeft()), rect.size())
px = self.label.pixmap()
tr = QtGui.QTransform()
tr.scale(px.size().width()*1.0/self.label.size().width(), px.size().height()*1.0/self.label.size().height())
r = tr.mapRect(r)
self.label.setPixmap(px.copy(r))