Q图形项目在移动后未停留在原位



我目前正在创建一个使用QGraphicsView的应用程序,该应用程序允许用户四处移动QGraphicsItems,这样他们就可以创建类似图表的结构。

我需要项目在单击时更改颜色,但在释放鼠标按钮时更改回其原始颜色。然而,当我定义"mouseReleaseEvent()"方法时,当我移动项目后单击视口上的任何位置时,它就会恢复到原始位置。

第一次移动项目后,如何使其保持原位?

为了更好地控制项目的定位,我尝试对场景使用"setSceneRef()",但它并没有解决问题。

我也无法使用CustomItem的"setPos()"方法解决问题。当同一场景中有多个项目时,坐标系似乎会发生变化。

另一个问题是,当鼠标放在其他项目上时,它们的颜色应该会发生变化。我尝试重写CustomItem类中的"hoverEnterEvent()"方法,但它不起作用。

下面是一个用于重现我所面临的问题的最小代码。

from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(QtWidgets.QMainWindow):
def __init__(self):
QtWidgets.QMainWindow.__init__(self)
self.setupUi(self)
self.main_menu = self.menuBar().addMenu("&Menu") 
self.addItem = QtWidgets.QAction("&Add Rectangle", self, triggered = self.addRectangle)
self.delItem = QtWidgets.QAction("&Delete Selected Rectangle(s)", self, triggered = self.delRectangle) 
self.main_menu.addAction(self.addItem) 
self.main_menu.addAction(self.delItem) 

self.scene = CustomScene(self.main_menu) 
self.graphicsView.setScene(self.scene)
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
self.verticalLayout.setObjectName("verticalLayout")
self.graphicsView = QtWidgets.QGraphicsView(self.centralwidget)
self.graphicsView.setObjectName("graphicsView")
self.verticalLayout.addWidget(self.graphicsView)
MainWindow.setCentralWidget(self.centralwidget)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
def addRectangle(self):
self.item = CustomItem()
self.scene.addItem(self.item)
self.scene.update()
def delRectangle(self):
for item in self.scene.selectedItems():
self.scene.removeItem(item)
class CustomScene (QtWidgets.QGraphicsScene):
def __init__(self, scene_menu, parent=None):
super(CustomScene, self).__init__(parent)
self.setSceneRect(0,0,750,500)
self.sceneMenu = scene_menu
def contextMenuEvent (self, event):
self.sceneMenu.exec_(event.screenPos()) 
class CustomItem (QtWidgets.QGraphicsRectItem):
def __init__(self, parent = None, scene = None):
super(CustomItem, self).__init__()
self.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable, True) 
self.setFlag(QtWidgets.QGraphicsItem.ItemIsSelectable, True) 
self.setRect(200,200,120,25) #Creates and show the rectangle
def contextMenuEvent(self, event): #Defines the menu shown on mouse right-click
self.scene().clearSelection()
self.setSelected(True)
self.RCMenu.exec_(event.screenPos()) 
def mousePressEvent(self, event):
self.setBrush(QtGui.QBrush(QtCore.Qt.cyan))
def hoverEnterEvent(self, event): #Not Working as intended, but it should change the rectangle's color to lightGray when I hover the mouse over it
self.setBrush(QtGui.QBrush(QtCore.Qt.lightGray))
def mouseReleaseEvent(self, event): # HERE IS THE REAL PROBLEM. WHENEVER I CLICK ON THE RECTANGLE AFTER IT'S RELEASE, IT GOES TO A SEEMINGLY RANDOM LOCATION
self.setBrush(QtGui.QBrush(QtCore.Qt.white))
if __name__ == "__main__":
import sys
if not QtWidgets.QApplication.instance():
app = QtWidgets.QApplication(sys.argv)
else:
app = QtWidgets.QApplication.instance()
window = Ui_MainWindow()
window.show()
sys.exit(app.exec_())

QGraphicsItem已经有了移动到新位置的行为,但当您由于删除父类的实现而覆盖这些行为时,如果您想保留该行为,则必须通过super调用父类的方法。

另一方面,您必须使用setAcceptHoverEvents(True)来启用悬停类型的事件。

有了上述解决方案:

class CustomItem (QtWidgets.QGraphicsRectItem):
def __init__(self, parent = None, scene = None):
super(CustomItem, self).__init__()
self.setAcceptHoverEvents(True)
self.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable, True) 
self.setFlag(QtWidgets.QGraphicsItem.ItemIsSelectable, True) 
self.setRect(200,200,120,25) #Creates and show the rectangle
def contextMenuEvent(self, event): #Defines the menu shown on mouse right-click
self.scene().clearSelection()
self.setSelected(True)
self.RCMenu.exec_(event.screenPos()) 
def mousePressEvent(self, event):
self.setBrush(QtGui.QBrush(QtCore.Qt.cyan))
super(CustomItem, self).mousePressEvent(event)
def mouseReleaseEvent(self, event):
self.setBrush(QtGui.QBrush(QtCore.Qt.white))
super(CustomItem, self).mouseReleaseEvent(event)
def hoverEnterEvent(self, event):
self.setBrush(QtGui.QBrush(QtCore.Qt.lightGray))
super(CustomItem, self).hoverEnterEvent(event)
def hoverLeaveEvent(self, event):
self.setBrush(QtGui.QBrush(QtCore.Qt.white))
super(CustomItem, self).hoverLeaveEvent(event)

另一方面,您用来删除项目的代码中存在问题,但现在它不可见,因为到目前为止,您只删除一个元素接一个元素,但当您想要删除一组元素时,您会看到问题,当您从列表中删除项目时,您必须从一开始就转到最后一个,因为如果您在访问未分配的内存时没有问题,在您的情况下,解决方案是:

def delRectangle(self):
for item in reversed(self.scene.selectedItems()):
self.scene.removeItem(item)

最新更新