PyQt5如何实现QGraphicsEllipseItem拖拽时绕另一图元平滑移动不重叠
问题根源
你当前的碰撞修正逻辑是直接将移动圆的x/y坐标固定到静止圆±最小距离的位置,所以最终只会落在四个对角位置,自然会出现吸附跳变的问题。要实现平滑绕行,需要基于两个圆心的相对角度做极坐标换算,保证移动圆始终和静止圆保持刚好不重叠的距离,且方向跟随你的拖拽偏移。
修复后完整代码
from PyQt5.QtCore import * from PyQt5.QtWidgets import * from PyQt5.QtGui import * import math class Circleitem(QGraphicsEllipseItem): def __init__(self, size, brush): super().__init__() radius = size / -2 self.setRect(radius, radius, size, size) self.setBrush(brush) self.setFlag(self.ItemIsMovable) self.setFlag(self.ItemIsSelectable) def paint(self, painter, option, a): option.state = QStyle.State_None return super(Circleitem, self).paint(painter,option) def mouseMoveEvent(self, event): super().mouseMoveEvent(event) self.scene().views()[0].parent().movearound() class MainWindow(QMainWindow): def __init__(self): super().__init__() self.gscene = QGraphicsScene(0, 0, 1000, 1000) gview = QGraphicsView(self.gscene) self.setCentralWidget(gview) self.circle1 = Circleitem (123, brush=QColor(255,255,0)) self.circle2 =Circleitem(80, brush=QColor(0,255,0)) self.gscene.addItem(self.circle1) self.gscene.addItem(self.circle2) self.circle1.setPos(500, 500) self.circle2.setPos(300, 300) self.show() def movearound(self): if not self.gscene.selectedItems(): return if self.gscene.selectedItems()[0] == self.circle1: moveditem = self.circle1 stillitem = self.circle2 else: moveditem = self.circle2 stillitem = self.circle1 # 计算两个圆心的相对坐标、实际距离、最小不碰撞距离 dx = moveditem.x() - stillitem.x() dy = moveditem.y() - stillitem.y() current_dist = math.hypot(dx, dy) min_dist = moveditem.rect().width()/2 + stillitem.rect().width()/2 # 距离小于最小值时触发修正 if current_dist < min_dist: # 处理两圆完全重合的除零情况 if current_dist == 0: angle = 0 else: # 计算当前相对角度 angle = math.atan2(dy, dx) # 按最小距离和当前角度计算新的位置 new_x = stillitem.x() + min_dist * math.cos(angle) new_y = stillitem.y() + min_dist * math.sin(angle) moveditem.setPos(new_x, new_y) app = QApplication([]) win = MainWindow() app.exec()
关键修改说明
- 删掉了原逻辑中无意义的距离缩放系数,最小不碰撞距离直接取两个圆的半径之和
- 用
math.hypot计算两个圆心的实际欧氏距离,替代原逻辑的x/y分别判断 - 基于相对角度做极坐标换算,修正后的位置始终在静止圆的最小距离圆周上,跟随拖拽方向平滑移动,不会出现跳变
- 增加了无选中项的判断,避免空索引报错
内容的提问来源于stack exchange,提问作者drivereye
相关产品推荐
相关产品推荐

