在 PyQt5 中从 QGraphicsScene 中选择项目
Selecting item from QGraphicsScene in PyQt5
我正在使用 QGraphicsView 和 QGraphicsSCene 加载图像。我在 QGraphicsScene 中有多个 RectItems。代码如下;
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 时,我都想打印该项目。
我认为最简单的解决方案,如果你真的只需要一个 "item clicked" 消息,就是向项目添加 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 的后代,这意味着它们不能发出任何信号。
如果你不需要signal/slot支持,你可以继承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(...)
如果您确实需要一些signal/slot机制,您也可以将场景子类化并使项目发出信号。这不是 最佳 做法,但它有效:-)
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),但是如果您添加其他项目类型,您将不得不更仔细地找到一种方法 "recognize" 它们。
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))
我正在使用 QGraphicsView 和 QGraphicsSCene 加载图像。我在 QGraphicsScene 中有多个 RectItems。代码如下;
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 时,我都想打印该项目。
我认为最简单的解决方案,如果你真的只需要一个 "item clicked" 消息,就是向项目添加 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 的后代,这意味着它们不能发出任何信号。
如果你不需要signal/slot支持,你可以继承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(...)
如果您确实需要一些signal/slot机制,您也可以将场景子类化并使项目发出信号。这不是 最佳 做法,但它有效:-)
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),但是如果您添加其他项目类型,您将不得不更仔细地找到一种方法 "recognize" 它们。
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))