QGraphicsItem не остается на месте после перемещения - PullRequest
0 голосов
/ 26 января 2019

В настоящее время я создаю приложение, которое использует 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 Ответ

0 голосов
/ 26 января 2019

У QGraphicsItem уже есть поведение перехода на новую позицию, но когда вы перезаписываете эти поведения, так как вы удаляете реализацию родительского класса, если вы хотите сохранить поведение, вы должны вызвать метод родительского класса. класс через супер.

С другой стороны, вы должны использовать 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)
...