Выбор элемента из QGraphicsScene в PyQt5 - PullRequest
0 голосов
/ 25 октября 2019

Я загружаю изображение, используя QGraphicsView и QGraphicsSCene. У меня есть несколько RectItems в QGraphicsScene. Код приведен ниже:

def load_image(self,image_item):
    rect_list = [[20,30,70,35],[50,100,60,100],[410,450,60,100]]
    self.pic = QPixmap(str(image_item.text()))
    self.scene = QGraphicsScene(self.centralWidget)
    self.brush = QBrush(Qt.BDiagPattern)
    self.pen = QPen(Qt.red)
    self.pen.setWidth(2)
    self.load_view = self.scene.addItem(QGraphicsPixmapItem(self.pic))
    for rect in rect_list:
        self.rect_item = self.scene.addRect(rect[0],rect[1],rect[2],rect[3],self.pen,self.brush) # x,y,w,h
        self.rect_item.setFlag(QGraphicsItem.ItemIsSelectable) #Item is Selectable
        self.rect_item.setFlag(QGraphicsItem.ItemIsMovable) # Item is Movable

    self.gView.setScene(self.scene)
    self.gView.setRenderHint(QPainter.Antialiasing)
    self.gView.show()

Теперь, когда я когда-либо нажимаю на один rect_item из списка элементов в QgraphicsScene, я хочу напечатать этот элемент.

Screenshot is given here

1 Ответ

0 голосов
/ 26 октября 2019

Я думаю, что самое простое решение, если вам действительно нужно только сообщение "элемент нажал", это добавить флаг Qt.ItemIsFocusable к элементу и затем использовать сигнал focusItemChanged сцены:

    def load_image(self, image_item):
        # ...
        self.scene = QGraphicsScene(self.centralWidget)
        self.scene.focusItemChanged.connect(self.focusChanged)
        # ...
        for rect in rect_list:
            self.rect_item = self.scene.addRect(rect[0],rect[1],rect[2],rect[3],self.pen,self.brush) # x,y,w,h
            self.rect_item.setFlag(QGraphicsItem.ItemIsSelectable)
            self.rect_item.setFlag(QGraphicsItem.ItemIsMovable)
            # required for focusItemChanged signal to work:
            self.rect_item.setFlag(QGraphicsItem.ItemIsFocusable)

    def focusItemChanged(self, newItem, oldItem, reason):
        if newItem and reason == Qt.MouseFocusReason:
            print('item {} clicked!'.format(newItem))

У этого метода есть некоторые проблемы, но, самое главное, тот факт, что если элемент уже выбран (следовательно, у него есть фокус), вы не получите сигнал.

Нет немедленного решения для этого, потому чтобазовые элементы QGraphicsItems не являются потомками QObject, что означает, что они не могут излучать какой-либо сигнал.

Если вам не требуется поддержка сигнала / слота, вы можете создать подкласс QGraphicsRectItem и переопределить его mousePressEvent:

class ClickableGraphicsRectItem(QGraphicsRectItem):
    def __init__(self, x, y, w, h, pen, brush):
        super(ClickableGraphicsRectItem, self).__init__(x, y, w, h)
        self.setPen(pen)
        self.setBrush(brush)
        # flags can be set all at once using the "|" binary operator
        self.setFlags(self.ItemIsSelectable|self.ItemIsMovable)

    def mousePressEvent(self, event):
        super(ClickableGraphicsRectItem, self).mousePressEvent(event)
        if event.button() == Qt.LeftButton:
            print('item clicked!')

class MyProgram(QMainWindow):
    def load_image(self, image_item):
        # ...
        for rect in rect_list:
            self.rect_item = ClickableGraphicsRectItem(...)

Если вам do нужен какой-то механизм сигнала / слота, вы также можете создать подкласс сцены и заставить элемент излучать свой сигнал. Это не лучшая практика, но она работает: -)

class ClickableGraphicsRectItem(QGraphicsRectItem):
    # ...
    def mousePressEvent(self, event):
        super(ClickableGraphicsRectItem, self).mousePressEvent(event)
        if event.button() == Qt.LeftButton:
            self.scene().itemClicked(self)

class ItemClickableGraphicsScene(QGraphicsScene):
    itemClicked = pyqtSignal(QGraphicsItem)

class MyProgram(QMainWindow):
    def load_image(self, image_item):
        # ...
        self.scene = ItemClickableGraphicsScene(self.centralWidget)
        self.scene.itemClicked.connect(self.itemClicked)
        # ...
        for rect in rect_list:
            self.rect_item = ClickableGraphicsRectItem(...)

    def itemClicked(self, item):
        print('item {} clicked!'.format(item))

В качестве альтернативы, вы можете переопределить mousePressEvent графического представления. В этом примере я просто проверяю, является ли это QGraphicsRectItem (поскольку у вас также есть QGraphicsPixmapItem), но если вы добавляете другие типы элементов, вам нужно будет найти способ «распознать» их более тщательно.

class ClickableItemView(QGraphicsView):
    def mousePressEvent(self, event):
        super(ClickableItemView, self).mousePressEvent(event)
        if event.button() == Qt.LeftButton:
            item = self.itemAt(event.pos())
            if isinstance(item, QGraphicsRectItem):
                print('item {} clicked!'.format(item))
...