从 PyQt5 中的 QGraphicsScene 中选择项目 [英] Selecting item from QGraphicsScene in PyQt5

查看:50
本文介绍了从 PyQt5 中的 QGraphicsScene 中选择项目的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 QGraphicsView 和 QGraphicsSCene 加载图像.我在 QGraphicsScene 中有多个 RectItems.代码如下;

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

现在,当我从 QgraphicsScene 的项目列表中单击一个 rect_item 时,我想打印该项目.

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

推荐答案

我认为最简单的解决方案,如果你真的只需要一个item clicked"消息,就是给 item 添加 Qt.ItemIsFocusable 标志,然后使用场景的focusItemChanged信号:

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.

对此没有直接的解决方案,因为基本的 QGraphicsItems 不是 QObject 的后代,这意味着它们不能发出任何信号.

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

如果您不需要信号/插槽支持,您可以继承 QGraphicsRectItem 并重新实现其 mousePressEvent:

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

或者,您可以重新实现图形视图的 mousePressEvent.在这个例子中,我只是检查它是否是 QGraphicsRectItem(因为你也有 QGraphicsPixmapItem),但如果你添加其他项目类型,你必须找到一种更仔细地识别"它们的方法.

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

这篇关于从 PyQt5 中的 QGraphicsScene 中选择项目的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆