pyqt要实现这样一个功能,QGraphicsView大小固定不变,当加载的图片尺寸大于QGraphicsView时,缩放图片适应QGraphicsView,当未超过时,保持原图居中显示,然后如果点击裁剪按钮,出现一个矩形裁剪框实现裁剪功能
时间: 2025-06-18 09:03:08 浏览: 13
### PyQt 中使用 QGraphicsView 实现图片自适应缩放、居中显示和裁剪功能
在 PyQt 的 `QGraphicsView` 和 `QGraphicsScene` 组件的帮助下,可以方便地实现图片的自适应缩放、居中显示以及裁剪功能。以下是详细的解决方案:
#### 自适应缩放与居中显示
为了使图片能够自动适配窗口大小并保持居中显示,可以通过设置视图的变换模式为 `KeepAspectRatio` 来确保比例不变,并利用 `fitInView()` 方法动态调整图片尺寸。
#### 裁剪功能
对于裁剪功能,可以在场景 (`QGraphicsScene`) 上绘制矩形选框,记录用户的拖拽动作以定义裁剪区域。之后提取该区域内像素数据完成裁剪操作。
下面是完整的示例代码:
```python
from PyQt5.QtWidgets import QApplication, QMainWindow, QGraphicsView, QGraphicsScene, QVBoxLayout, QWidget, QPushButton, QFileDialog
from PyQt5.QtGui import QPixmap, QImage, QPainter, QColor, QPen
from PyQt5.QtCore import Qt, QRectF
class ImageViewer(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setWindowTitle('Image Viewer with Crop')
centralWidget = QWidget(self)
layout = QVBoxLayout(centralWidget)
self.view = CustomGraphicsView(self)
self.scene = QGraphicsScene()
self.view.setScene(self.scene)
layout.addWidget(self.view)
buttonLoad = QPushButton("Load Image")
buttonCrop = QPushButton("Crop")
buttonLoad.clicked.connect(self.loadImage)
buttonCrop.clicked.connect(self.cropImage)
layout.addWidget(buttonLoad)
layout.addWidget(buttonCrop)
self.setCentralWidget(centralWidget)
def loadImage(self):
options = QFileDialog.Options()
fileName, _ = QFileDialog.getOpenFileName(self,"Select an image file", "", "Images (*.png *.jpg);;All Files (*)", options=options)
if fileName:
pixmap = QPixmap(fileName)
if not pixmap.isNull():
self.image = QImage(pixmap.toImage())
self.pixmap_item = self.scene.addPixmap(pixmap)
# Adjust view to fit the loaded image initially.
self.view.fitInView(self.pixmap_item, Qt.KeepAspectRatio)
def cropImage(self):
rect = self.view.getCropRect() # Get cropped rectangle coordinates.
if rect is None or self.image is None:
return
cropped_image = self.image.copy(rect) # Perform cropping using QImage's copy method.
savePath, _ = QFileDialog.getSaveFileName(None, 'Save Cropped Image', '', '*.png;;*.jpg')
if savePath and not savePath.strip().isspace():
cropped_image.save(savePath)
class CustomGraphicsView(QGraphicsView):
def __init__(self, parent=None):
super(CustomGraphicsView, self).__init__(parent)
self._is_panning = False
self._pan_start_x = 0
self._pan_start_y = 0
self.start_pos = None
self.end_pos = None
def wheelEvent(self, event):
factor = pow(1.2, event.angleDelta().y() / 240.0)
self.scale(factor, factor)
def resizeEvent(self, event):
super().resizeEvent(event)
scene_rect = self.sceneRect()
if not scene_rect.isEmpty():
self.fitInView(scene_rect, Qt.KeepAspectRatio)
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
self.start_pos = self.mapToScene(event.pos()) # Start position of selection box.
if self.itemAt(event.pos()):
self._is_panning = True
self._pan_start_x = event.x()
self._pan_start_y = event.y()
elif event.button() == Qt.RightButton:
self.resetTransform()
super().mousePressEvent(event)
def mouseMoveEvent(self, event):
if self._is_panning:
delta_x = event.x() - self._pan_start_x
delta_y = event.y() - self._pan_start_y
self.horizontalScrollBar().setValue(self.horizontalScrollBar().value() - delta_x)
self.verticalScrollBar().setValue(self.verticalScrollBar().value() - delta_y)
self._pan_start_x = event.x()
self._pan_start_y = event.y()
else:
current_pos = self.mapToScene(event.pos())
if self.start_pos:
pen = QPen(Qt.red, 2)
brush = QColor(255, 0, 0, 50)
painter = QPainter(self.viewport())
painter.setPen(pen)
painter.fillRect(QRectF(self.start_pos, current_pos), brush)
super().mouseMoveEvent(event)
def mouseReleaseEvent(self, event):
if event.button() == Qt.LeftButton:
self._is_panning = False
self.end_pos = self.mapToScene(event.pos()) # End position of selection box.
super().mouseReleaseEvent(event)
def getCropRect(self):
"""Return a QRect object representing the selected area."""
if self.start_pos and self.end_pos:
top_left = min(self.start_pos.x(), self.end_pos.x()), min(self.start_pos.y(), self.end_pos.y())
bottom_right = max(self.start_pos.x(), self.end_pos.x()), max(self.start_pos.y(), self.end_pos.y())
width = abs(bottom_right[0] - top_left[0])
height = abs(bottom_right[1] - top_left[1])
return QRectF(top_left[0], top_left[1], width, height).toAlignedRect()
if __name__ == '__main__':
app = QApplication([])
window = ImageViewer()
window.showMaximized()
app.exec_()
```
此程序实现了加载图片后的自适应缩放、鼠标滚轮控制放大缩小的功能[^1],还支持通过左键拖动选择裁剪范围,并最终保存裁剪结果到本地文件[^2]。
阅读全文
相关推荐

















