blockSignals не работает для QGraphicsScene SelectionChanged

#python #pyqt5

Вопрос:

selectionChanged Сигнал срабатывает после того, как я отменяю выбор выбранного элемента, несмотря на то, что звонил blockSignals(True) незадолго до этого. Вы можете видеть, что круг будет перемещен дважды, а не один раз. Почему это происходит и как я могу предотвратить срабатывание сигнала?

 import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *

class Template(QMainWindow):

    def __init__(self):
        super().__init__()
        self.scene = QGraphicsScene(0, 0, 200, 400)
        c = self.scene.addEllipse(8, 8, 34, 34, Qt.black, Qt.black)
        c.setPos(0, 350)
        c.setFlag(QGraphicsItem.ItemIsSelectable)
        self.scene.selectionChanged.connect(self.move)
        
        view = QGraphicsView(self.scene)
        view.setRenderHint(QPainter.Antialiasing)
        self.setCentralWidget(view)        

    def move(self):
        selected = self.scene.selectedItems()
        if selected:
            selected[0].moveBy(0, -50)
            self.scene.blockSignals(True)
            selected[0].setSelected(False)
            self.scene.blockSignals(False)

        
if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = Template()
    window.show()
    sys.exit(app.exec_())
 

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

Меня интересует общий случай: selectionChanged сигнал подключен к слоту, и в этой функции вам нужно отменить выбор элемента без повторного вызова слота.

Комментарии:

1. Почему вам нужно немедленно отменить выбор элемента? Является ли ваша цель звонить move только тогда, когда элемент нажат? В этом случае вам не следует использовать выделение.

2. Да, логика «пометки», очевидно, имеет здесь больше смысла. Мне было просто любопытно, почему это была двойная стрельба, и я хотел привести очень маленький и простой пример.

Ответ №1:

Проблема вызвана мышью, так как после выполнения логики перемещения мыши она все еще находится на элементе, вызывающем его выбор, генерирующий этот двойной снимок. Возможное решение-отменить выбор после того, как мышь будет отпущена.

 class GraphicsScene(QGraphicsScene):
    def mouseReleaseEvent(self, event):
        super().mouseReleaseEvent(event)
        for item in self.selectedItems():
            item.setSelected(False)
        self.blockSignals(False)


class Template(QMainWindow):
    def __init__(self):
        super().__init__()
        self.scene = GraphicsScene(0, 0, 200, 400, self)
        self.scene.selectionChanged.connect(self.handle_selection_changed)

        c = self.scene.addEllipse(8, 8, 34, 34, Qt.black, Qt.black)
        c.setPos(0, 350)
        c.setFlag(QGraphicsItem.ItemIsSelectable)

        view = QGraphicsView(self.scene)
        view.setRenderHint(QPainter.Antialiasing)
        self.setCentralWidget(view)

    def handle_selection_changed(self):
        self.scene.blockSignals(True)
        for item in self.scene.selectedItems():
            item.moveBy(0, -50)