QGraphicsItem не остается на месте после перемещения

В настоящее время я создаю приложение, которое использует QGraphicsView и позволяет пользователю перемещать элементы QGraphicsItems, чтобы они могли создавать диаграммоподобные структуры.

Мне нужно, чтобы элементы меняли цвет при щелчке, но возвращались к исходному цвету при отпускании кнопки мыши. Однако, когда я определяю метод "mouseReleaseEvent()", элемент просто возвращается в исходное положение, когда я щелкаю в любом месте области просмотра после его перемещения.

Как я могу заставить Предмет оставаться на месте после его перемещения в первый раз?

Чтобы иметь больше контроля над позиционированием элемента, я попытался использовать "setSceneRect()" для сцены, но это не решило проблему.

Я не мог решить проблему, используя метод setPos () CustomItem либо. Кажется, система координат меняется, когда на одной сцене несколько элементов.

Дополнительной проблемой является то, что некоторые другие элементы должны менять цвет, когда мышь над ними. Я попытался переопределить метод "hoverEnterEvent ()" в классе CustomItem, но он не работает.

Вот минимальный код для воспроизведения проблемы, с которой я сталкиваюсь.

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_())

1 ответ

Решение

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)
Другие вопросы по тегам