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))