Python MousePresseEvent禁用QGraphicsItem ItemIsMovable
我想在Python MousePresseEvent禁用QGraphicsItem ItemIsMovable,python,qgraphicsscene,pyside2,Python,Qgraphicsscene,Pyside2,我想在QGraphicsView中的qgraphicscene中显示的图像上画圆圈(参见屏幕截图) 我目前通过覆盖自定义qgraphicscene对象的mousePressEvent来放置红色圆圈,但是这似乎阻止了鼠标事件传播到形成圆圈的qgraphicselipseItems。这是一个耻辱,因为我希望这些保持可移动和可选择。我目前的做法是维护生成的QGraphicsItems列表,并简单地循环它们,调用它们的事件处理程序,例如: def mouseMoveEvent(self, event)
QGraphicsView
中的qgraphicscene
中显示的图像上画圆圈(参见屏幕截图)
我目前通过覆盖自定义qgraphicscene
对象的mousePressEvent
来放置红色圆圈,但是这似乎阻止了鼠标事件传播到形成圆圈的qgraphicselipseItem
s。这是一个耻辱,因为我希望这些保持可移动和可选择。我目前的做法是维护生成的QGraphicsItem
s列表,并简单地循环它们,调用它们的事件处理程序,例如:
def mouseMoveEvent(self, event):
for circ in self.circs:
if circ.rect().contains(event.scenePos()) or circ.isSelected():
circ.mouseMoveEvent(event)
这一系列的工作,但似乎有点麻烦(有时省略号变得不可选择)。我应该提到的是,来自的解决方案对我不起作用。如果我尝试使用类似于QtGui.QGraphicsItem.mouseMoveEvent(self,event)
的方法传播事件,则会出现以下错误:
Traceback (most recent call last):
File "main.py", line 58, in mouseMoveEvent
QtGui.QGraphicsItem.mouseMoveEvent(self, event)
AttributeError: module 'PySide2.QtGui' has no attribute 'QGraphicsItem'
那么,什么是正确和正确的方法呢?下面是一个代码示例
main.py:
from PySide2.QtCore import *
from PySide2.QtGui import *
from PySide2.QtWidgets import *
from PySide2 import QtWidgets, QtGui
import ui.main_window as main_window
import sys
import data_loader.data_loaders as module_data
import cv2 as cv
img_default_size = (512, 512)
class WingSceneWidget(QtWidgets.QGraphicsScene):
def __init__(self, parent):
super(self.__class__, self).__init__(parent)
self.keypoints = []
self.annotating = False
self.p_item = None
self.circs = []
def mouseDoubleClickEvent(self, event):
print("New Annotation")
self.annotating = True
self.keypoints = []
for circ in self.circs:
self.removeItem(circ)
def mousePressEvent(self, event):
circ_radius = 5
if self.annotating:
x = event.scenePos().x()
y = event.scenePos().y()
self.keypoints.append([x, y])
circ = QGraphicsEllipseItem(x-circ_radius, y-circ_radius, circ_radius*2, circ_radius*2, self.p_item)
circ.setPen(QPen(Qt.red, 2))
circ.setFlag(QGraphicsItem.ItemIsMovable, True)
circ.setFlag(QGraphicsItem.ItemIsSelectable, True)
self.circs.append(circ)
print(self.keypoints)
if len(self.keypoints) >= 8:
self.annotating = False
for circ in self.circs:
if circ.rect().contains(event.scenePos()):
circ.mousePressEvent(event)
def mouseMoveEvent(self, event):
for circ in self.circs:
if circ.rect().contains(event.scenePos()) or circ.isSelected():
circ.mouseMoveEvent(event)
def mouseReleaseEvent(self, event):
for circ in self.circs:
if circ.rect().contains(event.scenePos()) or circ.isSelected():
circ.mouseReleaseEvent(event)
def give_pitem(self, p_item):
self.p_item = p_item
class WingNet(QtWidgets.QMainWindow, main_window.Ui_MainWindow):
def __init__(self):
super(self.__class__, self).__init__()
self.setupUi(self)
self.folder_list = []
self.scene = WingSceneWidget(self.gv_wing_image)
self.gv_wing_image.setScene(self.scene)
self.gv_wing_image.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform)
self.btn_label_wings.clicked.connect(self.browse_folders)
self.listWidget.currentItemChanged.connect(self.selection_changed)
def browse_folders(self):
self.listWidget.clear() # In case there are any existing elements in the list
file_dialog = QtWidgets.QFileDialog()
file_dialog.setFileMode(QtWidgets.QFileDialog.DirectoryOnly)
file_dialog.setOption(QtWidgets.QFileDialog.DontUseNativeDialog, True)
file_view = file_dialog.findChild(QtWidgets.QListView, 'listView')
# to make it possible to select multiple directories:
if file_view:
file_view.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection)
f_tree_view = file_dialog.findChild(QtWidgets.QTreeView)
if f_tree_view:
f_tree_view.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection)
if file_dialog.exec():
self.folder_list = file_dialog.selectedFiles()
if self.folder_list:
image_paths = module_data.get_image_paths(self.folder_list)
for image_path in image_paths:
print(image_path)
self.listWidget.addItem(image_path)
self.btn_edit_tps.setEnabled(False)
self.btn_label_wings.setText("Start")
self.btn_label_wings.clicked.disconnect()
def selection_changed(self):
selected = self.listWidget.currentItem().text()
print(selected)
image = cv.imread(selected)
image = cv.resize(image, img_default_size)
height, width, channel = image.shape
bytes_per_line = 3 * width
q_img = QtGui.QImage(image.data, width, height, bytes_per_line, QtGui.QImage.Format_RGB888).rgbSwapped()
pixmap = QtGui.QPixmap.fromImage(q_img)
p_item = self.scene.addPixmap(pixmap)
self.scene.give_pitem(p_item)
def main():
app = QtWidgets.QApplication(sys.argv)
form = WingNet()
form.show()
app.exec_()
if __name__ == '__main__':
main()
main_window.py:
from PySide2 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(803, 616)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
self.verticalLayout.setObjectName("verticalLayout")
self.splitter_image_list = QtWidgets.QSplitter(self.centralwidget)
self.splitter_image_list.setOrientation(QtCore.Qt.Horizontal)
self.splitter_image_list.setObjectName("splitter_image_list")
self.gv_wing_image = QtWidgets.QGraphicsView(self.splitter_image_list)
self.gv_wing_image.setObjectName("gv_wing_image")
self.listWidget = QtWidgets.QListWidget(self.splitter_image_list)
self.listWidget.setObjectName("listWidget")
self.verticalLayout.addWidget(self.splitter_image_list)
self.h_layout_buttons = QtWidgets.QHBoxLayout()
self.h_layout_buttons.setObjectName("h_layout_buttons")
self.btn_edit_tps = QtWidgets.QPushButton(self.centralwidget)
self.btn_edit_tps.setObjectName("btn_edit_tps")
self.h_layout_buttons.addWidget(self.btn_edit_tps)
self.btn_label_wings = QtWidgets.QPushButton(self.centralwidget)
self.btn_label_wings.setObjectName("btn_label_wings")
self.h_layout_buttons.addWidget(self.btn_label_wings)
self.verticalLayout.addLayout(self.h_layout_buttons)
MainWindow.setCentralWidget(self.centralwidget)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.menuBar = QtWidgets.QMenuBar(MainWindow)
self.menuBar.setGeometry(QtCore.QRect(0, 0, 803, 25))
self.menuBar.setObjectName("menuBar")
MainWindow.setMenuBar(self.menuBar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
MainWindow.setWindowTitle(QtWidgets.QApplication.translate("MainWindow", "MainWindow", None, -1))
self.btn_edit_tps.setText(QtWidgets.QApplication.translate("MainWindow", "Edit Existing TPS", None, -1))
self.btn_label_wings.setText(QtWidgets.QApplication.translate("MainWindow", "Label New Wings", None, -1))
由于您要覆盖场景mousePressEvent,因此必须自己检查鼠标坐标处存在的项目;这可以通过使用
qgraphicscene.items()
来实现,它以z索引顺序(从上到下)返回这些坐标处的项目列表
在您的情况下,只需确保某些项存在,并且最上面的是QGraphicsSellipseitem;如果是这种情况,只需继续进行基类实现,否则添加点。这也意味着您不必重写mouseMoveEvent或mouseReleaseEvent
def mousePressEvent(self,event):
items=self.items(event.scenePos())
如果items和isinstance(items[0],QGraphicsSellipseitem):
qtwidts.qgraphicscene.mousePressEvent(self,event)
返回
如果自注释:
圆周半径=5
x=event.scenePos().x()
y=event.scenePos().y()
self.keypoints.append([x,y])
circ=QGraphicsSellipseitem(x-circ_半径、y-circ_半径、circ_半径*2、circ_半径*2、self.p_项)
电路设置笔(QPen(Qt.red,2))
circ.setFlags(circ.flags()| QGraphicsItem.ItemIsMovable | QGraphicsItem.itemisselect)
如果len(自关键点)>=8:
self.annotating=False
为便于将来参考,请尽量提供最少且可重复的示例:不需要整个加载机制,也不需要cv模块依赖关系。感谢您的帮助,这非常有效。对不起,代码太多了,我宁愿犯错误,给的太多而不是太少。不客气,别担心,我能理解你的观点。请记住,即使在理解实际问题之前,也不是每个人都希望在发现代码难以正常工作时提供帮助。有时,“付出太多”(特别是如果它与手头的问题无关)可能是一个问题,您可能会遇到这样的风险:实际上可以帮助您的人甚至在尝试之前就放弃了,因为他们可能没有足够的时间来理清如何让您的代码一开始就运行。