gpt4 book ai didi

python - PyQt4 - 拖动后 QGraphicsItem 位置未正确映射到场景中

转载 作者:行者123 更新时间:2023-12-01 04:34:06 28 4
gpt4 key购买 nike

我创建了一个基于 QWidgetImageView 小部件,其中包含一个 QGraphicsView。该小部件显示图像,并允许您通过 QGraphicsRectItem 用鼠标绘制 ROI(感兴趣区域)。ImageView 小部件运行良好,但如果拖动 ROI 矩形并且您想在其他位置重绘它,则鼠标事件捕获的位置无法正确映射到场景。

这里有一些图片来解释我的意思。

包含 ImageView 小部件的对话框,其操作控制小部件本身:

enter image description here

如果启用选择,您可以绘制一个矩形:

enter image description here

注意矩形右下角的指针位置。 ROI 只能在图像内部绘制。

如果禁用选择,您可以拖动之前绘制的矩形:

enter image description here

此后,如果启用选择并且您想要重绘矩形:

enter image description here

指针位置被捕获得很好(这是事实!),正如您在对话框状态栏上看到的那样,但是这个位置(用于设置矩形几何形状)不再对应于矩形位置。

我对 Qt 还很陌生,代码如下:

代码

class ImageView(QtGui.QWidget):
scaleChanged = QtCore.pyqtSignal()
statusChanged = QtCore.pyqtSignal(str)

def __init__(self, parent=None):
super(ImageView, self).__init__(parent)
self.scale_factor = 0.0

# Imagen
self.image_item = QtGui.QGraphicsPixmapItem()

# ROI
self.ROI_item = FancyQGraphicsRectItem(self.image_item)
self.ROI_item.setFlag(self.ROI_item.ItemIsMovable)
self.ROI_item.setBrush(QtGui.QBrush(QtCore.Qt.NoBrush))
self.ROI_item.setPen(QtGui.QPen(QtCore.Qt.white, 0, QtCore.Qt.DashDotLine))
self.ROI_item.setCursor(QtCore.Qt.OpenHandCursor)
self.ROI_added = False

# Escena
self.scene = QtGui.QGraphicsScene()

# Vista
self.view = FancyQGraphicsView()
self.view.ROI_item = self.ROI_item
self.view.statusChanged.connect(self.change_status)
self.view.setScene(self.scene)
self.view.setBackgroundRole(QtGui.QPalette.Dark)
self.view.setAlignment(QtCore.Qt.AlignCenter)
self.view.setFrameShape(QtGui.QFrame.NoFrame)
self.view.setRenderHint(QtGui.QPainter.Antialiasing, False)
self.view.setMouseTracking(True)

# Disposición
layout = QtGui.QVBoxLayout()
layout.setContentsMargins(0, 0, 0, 0)
layout.addWidget(self.view)

self.setLayout(layout)

def setImage(self, pixmap):
self.image_item.setPixmap(pixmap)
self.scene.addItem(self.image_item)
self.scene.setSceneRect(0, 0, self.image_item.boundingRect().right(), self.image_item.boundingRect().bottom())
self.view.setSceneSize()

def selectionEnable(self, value):
self.view.selectionEnable(value)
if value:
self.ROI_item.setCursor(QtCore.Qt.CrossCursor)
self.view.setInteractive(False)
self.view.viewport().setCursor(QtCore.Qt.CrossCursor)
if not self.ROI_added:
self.ROI_added = True
else:
self.view.viewport().setCursor(QtCore.Qt.ArrowCursor)
self.ROI_item.setCursor(QtCore.Qt.OpenHandCursor)
self.view.setInteractive(True)

def setupDrag(self, value):
if value:
self.view.setInteractive(False)
self.view.setDragMode(self.view.ScrollHandDrag)
else:
self.view.setDragMode(self.view.NoDrag)
self.view.setInteractive(True)

def normal_size(self):
if self.scale_factor != 1.0:
self.view.resetMatrix()
self.scale_factor = 1.0
self.scaleChanged.emit()

def scale_image(self, factor):
self.scale_factor *= factor
self.view.scale(factor, factor)
self.scaleChanged.emit()

def delete_roi(self):
self.ROI_item.setRect(0, 0, 0, 0)

@QtCore.pyqtSlot(str)
def change_status(self, message):
self.statusChanged.emit(message)


class FancyQGraphicsView(QtGui.QGraphicsView):
statusChanged = QtCore.pyqtSignal(str)
scene_size = (0, 0)
ROI_item = None
event_origin = None
selection = False
click = False

def mousePressEvent(self, event):
if self.selection:
event_pos = self.mapToScene(event.pos())
pos = (int(event_pos.x()), int(event_pos.y()))
if 0 <= pos[0] < self.scene_size[0] and 0 <= pos[1] < self.scene_size[1]:
self.event_origin = event_pos
else:
self.event_origin = None
self.click = True
else:
QtGui.QGraphicsView.mousePressEvent(self, event)

def mouseMoveEvent(self, event):
event_pos = self.mapToScene(event.pos())
if self.selection and self.click:
if self.event_origin:
self.statusChanged.emit("x1: {0:>5d} y1: {1:>5d} "
"x2: {2:>5d} y2: {3:>5d}".format(int(self.event_origin.x()),
int(self.event_origin.y()),
int(event_pos.x()),
int(event_pos.y())))
if event_pos.x() < 0:
event_pos.setX(0)
elif event_pos.x() > self.scene_size[0] - 1:
event_pos.setX(self.scene_size[0] - 1)
if event_pos.y() < 0:
event_pos.setY(0)
elif event_pos.y() > self.scene_size[1] - 1:
event_pos.setY(self.scene_size[1] - 1)
self.ROI_item.setRect(QtCore.QRectF(self.event_origin, event_pos).normalized())
print self.ROI_item.rect(), self.event_origin, event_pos
else:
self.statusChanged.emit("x: {0:>5d} y: {1:>5d}".format(int(event_pos.x()), int(event_pos.y())))
else:
self.statusChanged.emit("x: {0:>5d} y: {1:>5d}".format(int(event_pos.x()), int(event_pos.y())))
QtGui.QGraphicsView.mouseMoveEvent(self, event)

def mouseReleaseEvent(self, event):
if self.selection:
self.click = False
if self.event_origin:
self.event_origin = None
else:
QtGui.QGraphicsView.mouseReleaseEvent(self, event)

def selectionEnable(self, value):
self.selection = value

def setSceneSize(self):
rect = self.scene().sceneRect()
self.scene_size = (rect.width(), rect.height())


class FancyQGraphicsRectItem(QtGui.QGraphicsRectItem):

def mousePressEvent(self, event):
self.setCursor(QtCore.Qt.ClosedHandCursor)
QtGui.QGraphicsRectItem.mousePressEvent(self, event)

def mouseMoveEvent(self, event):
QtGui.QGraphicsRectItem.mouseMoveEvent(self, event)
# Maybe this could be modified

def mouseReleaseEvent(self, event):
self.setCursor(QtCore.Qt.OpenHandCursor)
QtGui.QGraphicsRectItem.mouseReleaseEvent(self, event)

为什么会发生这种情况?以前,我尝试在矩形的图像中实现受限的可移动区域,但该项目在拖动时无法正确识别其在场景中的位置。

最佳答案

您的问题是由于您使用QGraphicsRectItem的方式造成的。当您最初正确设置矩形时,该项目最初放置在场景的坐标 (0,0) 处。因此,QGraphicsRectItem(0,0) 延伸到矩形的右下角坐标(在场景坐标中)。

当您移动 ROI 时,您将平移整个项目,而不仅仅是项目内的矩形。这意味着该项目不再位于 (0,0),因此您输入的坐标会发生偏移,因为您使用的是场景坐标而不是项目坐标。

有多种方法(例如QGraphicsItem.mapFromScene())可以将坐标转换为正确的引用点(请注意,这应该考虑到您的 ROI 是 ROI 的子级) self.image_item 以及如果它从 (0,0) 移开的话。

另一种选择是,您可以将 ROI 重新定位到初始单击坐标,然后根据初始单击坐标和当前单击坐标之间的差异调整其大小。所以在 mouseMoveEvent 中你可以这样做:

self.ROI_item.setPos(self.event_origin)
self.ROI_item.setRect(QtCore.QRectF(QtCore.QPointF(0,0), event_pos-self.event_origin).normalized())

但是,我怀疑如果移动父项,或者对 QGraphicsView 应用缩放,则可能会中断。在这种情况下,您可能需要使用 QGraphicsItem.mapFromScene() 方法进行研究(尽管始终将项目重新定位到初始单击位置可能很有用,如果只是为了缩小边界框)的项目)

关于python - PyQt4 - 拖动后 QGraphicsItem 位置未正确映射到场景中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32018223/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com