当前位置:   article > 正文

PYQT5实现图片显示、通过滚轮缩放图片、通过鼠标拖动图片移动,搞懂所有细节_pyqt5:qpainter绘制基础图形,鼠标拖动

pyqt5:qpainter绘制基础图形,鼠标拖动

本文在这篇文章的基础上进行优化:

pyqt5实现图片显示、图片放大/缩小(通过滚轮)、图片移动(鼠标拖动)_小郁同学的博客-CSDN博客_pyqt5 放大图片

 首先要说明2个重要细节:
一般触发paintEvent事件的有如下几种原因:

窗口显隐导致重画
窗口大小(重新调整)改变,或者重新排布(布局)导致重画
调用update 或者 repaint重画
当窗口第一次显示时,系统会自动产生绘图事件
当窗口部件被其他部件遮挡时,然后又再次显示出来,会对隐藏区域进行重绘事件
————————————————
原文链接:https://blog.csdn.net/liunanya/article/details/93844597

在案例中,如果窗口已打开图片,再次打开图片时,会弹出图片选择框,图片选择框会遮挡图片显示控件,这个操作将触发paintEvent事件。如果设置图片左上角的点QPoint为(0,0)倒没什么问题,一旦不是(0,0)将会出错,因为在其它分支会重新计算QPoint。

很多意想不到的地方会触发paintEvent事件

第2个细节:

painter.drawPixmap(self.point, self.scaled_img)

中,self.point不是图片显示的左上角真实值,需要除以scale才是,形如self.point / self.scale,参考文献中似乎也未留意到这一点。

我的案例优化点:

1.初始图片居中显示

2.缩放:如鼠标点在图上,则根据这一点顶点缩放,否则按图此前的左上角点进行缩放

3.图片拖动时,左键按住的点不会漂移

代码如下:

  1. # -*- coding: utf-8 -*-
  2. import sys
  3. from PyQt5 import QtCore, QtGui, QtWidgets
  4. from PyQt5.QtGui import QImageReader
  5. from PyQt5.QtWidgets import QWidget, QApplication, QVBoxLayout, QHBoxLayout, QPushButton, QLabel, QFileDialog
  6. from PyQt5.Qt import QPixmap, QPoint, Qt, QPainter, QIcon
  7. from PyQt5.QtCore import QSize
  8. class ImageBox(QWidget):
  9. def __init__(self):
  10. super(ImageBox, self).__init__()
  11. self.img = None
  12. self.scaled_img = None
  13. self.start_pos = None
  14. self.end_pos = None
  15. self.left_click = False
  16. self.wheel_flag = False
  17. self.scale = 1
  18. self.old_scale = 1
  19. self.point = QPoint(0, 0)
  20. self.x = -1
  21. self.y = -1
  22. self.new_height = -1
  23. self.new_width = -1
  24. def init_ui(self):
  25. self.setWindowTitle("ImageBox")
  26. def set_image(self, img_path):
  27. self.img = QPixmap(img_path)
  28. width, height = self.img.width(), self.img.height()
  29. if height / width > 990 / 660:
  30. new_height = 990
  31. new_width = width * 990 / height
  32. else:
  33. new_height = height * 660 / width
  34. new_width = 660
  35. self.point = QPoint(int((660 - new_width) * 0.5), int((990 - new_height) * 0.5))
  36. self.img = self.img.scaled(new_width, new_height, Qt.KeepAspectRatio)
  37. self.scaled_img = self.img
  38. self.new_height = new_height
  39. self.new_width = new_width
  40. self.scale = 1
  41. def paintEvent(self, e):
  42. if self.scaled_img:
  43. painter = QPainter()
  44. painter.begin(self)
  45. painter.scale(self.scale, self.scale)
  46. if self.wheel_flag: # 定点缩放
  47. self.wheel_flag = False
  48. # 判断当前鼠标pos在不在图上
  49. this_left_x = self.point.x() * self.old_scale
  50. this_left_y = self.point.y() * self.old_scale
  51. this_scale_width = self.new_width * self.old_scale
  52. this_scale_height = self.new_height * self.old_scale
  53. # 鼠标点在图上,以鼠标点为中心动作
  54. gap_x = self.x - this_left_x
  55. gap_y = self.y - this_left_y
  56. if 0 < gap_x < this_scale_width and 0 < gap_y < this_scale_height:
  57. new_left_x = int(self.x / self.scale - gap_x / self.old_scale)
  58. new_left_y = int(self.y / self.scale - gap_y / self.old_scale)
  59. self.point = QPoint(new_left_x, new_left_y)
  60. # 鼠标点不在图上,固定左上角进行缩放
  61. else:
  62. true_left_x = int(self.point.x() * self.old_scale / self.scale)
  63. true_left_y = int(self.point.y() * self.old_scale / self.scale)
  64. self.point = QPoint(true_left_x, true_left_y)
  65. painter.drawPixmap(self.point, self.scaled_img) # 此函数中还会用scale对point进行处理
  66. painter.end()
  67. def wheelEvent(self, event):
  68. angle = event.angleDelta() / 8 # 返回QPoint对象,为滚轮转过的数值,单位为1/8度
  69. angleY = angle.y()
  70. self.old_scale = self.scale
  71. self.x, self.y = event.x(), event.y()
  72. self.wheel_flag = True
  73. # 获取当前鼠标相对于view的位置
  74. if angleY > 0:
  75. self.scale *= 1.08
  76. else: # 滚轮下滚
  77. self.scale *= 0.92
  78. if self.scale < 0.3:
  79. self.scale = 0.3
  80. self.adjustSize()
  81. self.update()
  82. def mouseMoveEvent(self, e):
  83. if self.left_click:
  84. self.end_pos = e.pos() - self.start_pos # 当前位置-起始位置=差值
  85. self.point = self.point + self.end_pos / self.scale # 左上角的距离变化
  86. self.start_pos = e.pos()
  87. self.repaint()
  88. def mousePressEvent(self, e):
  89. if e.button() == Qt.LeftButton:
  90. self.left_click = True
  91. self.start_pos = e.pos()
  92. def mouseReleaseEvent(self, e):
  93. if e.button() == Qt.LeftButton:
  94. self.left_click = False
  95. class Ui_Form(QWidget):
  96. def setupUi(self, Form):
  97. Form.setObjectName("Form")
  98. Form.resize(900, 1080)
  99. self.scrollArea = QtWidgets.QScrollArea(Form)
  100. self.scrollArea.setGeometry(QtCore.QRect(150, 10, 680, 990))
  101. self.scrollArea.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
  102. self.scrollArea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
  103. # self.scrollArea.setWidgetResizable(True)
  104. self.scrollArea.setObjectName("scrollArea")
  105. self.scrollAreaWidgetContents = QtWidgets.QWidget()
  106. self.box = ImageBox()
  107. self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 680, 990))
  108. self.scrollAreaWidgetContents.setMinimumSize(QtCore.QSize(100, 100))
  109. self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents")
  110. self.gridLayout = QtWidgets.QGridLayout(self.scrollAreaWidgetContents)
  111. self.gridLayout.setObjectName("gridLayout")
  112. self.gridLayout.addWidget(self.box, 0, 0, 1, 1)
  113. self.scrollArea.setWidget(self.scrollAreaWidgetContents)
  114. self.open_file = QtWidgets.QPushButton(Form)
  115. self.open_file.setGeometry(QtCore.QRect(30, 100, 81, 41))
  116. font = QtGui.QFont()
  117. font.setFamily("Aharoni")
  118. font.setPointSize(10)
  119. font.setBold(True)
  120. font.setWeight(75)
  121. self.open_file.setFont(font)
  122. self.open_file.setObjectName("open_file")
  123. self.open_file.clicked.connect(self.open_image)
  124. self.retranslateUi(Form)
  125. QtCore.QMetaObject.connectSlotsByName(Form)
  126. def retranslateUi(self, Form):
  127. _translate = QtCore.QCoreApplication.translate
  128. Form.setWindowTitle(_translate("Form", "Form"))
  129. self.open_file.setText(_translate("Form", "选择文件"))
  130. def open_image(self):
  131. img_name, _ = QFileDialog.getOpenFileName(None, "Open Image File","","All Files(*);;*.jpg;;*.png;;*.jpeg")
  132. self.box.set_image(img_name)
  133. if __name__ == "__main__":
  134. app = QtWidgets.QApplication(sys.argv)
  135. MainWindow = QtWidgets.QMainWindow()
  136. ui = Ui_Form()
  137. ui.setupUi(MainWindow)
  138. MainWindow.show()
  139. sys.exit(app.exec_())

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/100715
推荐阅读
相关标签
  

闽ICP备14008679号