Selecting item from QGraphicsScene in PyQt5

自作多情 提交于 2019-12-25 18:53:32

问题


I am loading image using QGraphicsView and QGraphicsSCene. I have multiple RectItems in QGraphicsScene. Code is given below;

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

Now, When ever I click on one rect_item from the item list in QgraphicsScene, I want to print that item.


回答1:


I think that the most simple solution, if you really need an "item clicked" message only, is to add Qt.ItemIsFocusable flag to the item and then use the focusItemChanged signal of the scene:

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

This method has some issues, though, most importantly the fact that if an item is already selected (hence, it has focus) you won't get the signal.

There's no immediate solution for this, because basic QGraphicsItems are not QObject descendants, meaning that they cannot emit any signal.

If you don't need signal/slot support, you can subclass QGraphicsRectItem and reimplement its 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(...)

If you do need some signal/slot mechanism, you could subclass the scene also and make the item emit its signal. This is not the best practice, but it works :-)

class ClickableGraphicsRectItem(QGraphicsRectItem):
    # ...
    def mousePressEvent(self, event):
        super(ClickableGraphicsRectItem, self).mousePressEvent(event)
        if event.button() == Qt.LeftButton:
            self.scene().itemClicked.emit(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))

Alternatively, you can reimplement the mousePressEvent of the graphics view. In this example I just check if it's a QGraphicsRectItem (since you also have the QGraphicsPixmapItem), but if you add other item types you'll have to find a way to "recognize" them more carefully.

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


来源:https://stackoverflow.com/questions/58555164/selecting-item-from-qgraphicsscene-in-pyqt5

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!