PyQt5: Questions about QGraphicsScene's itemAt() and focusItemChanged()

房东的猫 提交于 2021-02-08 06:54:23

问题


I have two questions:

  1. what does QTransform() mean in itemAt()? The sentence below is what it says in Qt doc, but I can't understand:

deviceTransform is the transformation that applies to the view, and needs to be provided if the scene contains items that ignore transformations.

  1. why focusItemChanged signal is not working?

Here is my code:

import sys
from PyQt5.QtGui import QTransform
from PyQt5.QtWidgets import QApplication, QGraphicsItem, QGraphicsScene, QGraphicsView


class Demo(QGraphicsView):
    def __init__(self):
        super(Demo, self).__init__()
        self.resize(300, 300)

        self.scene = QGraphicsScene()
        self.scene.setSceneRect(0, 0, 300, 300)

        self.rect = self.scene.addRect(100, 30, 100, 30)
        self.ellipse = self.scene.addEllipse(100, 80, 50, 40)

        self.rect.setFlags(QGraphicsItem.ItemIsMovable | QGraphicsItem.ItemIsSelectable)
        self.ellipse.setFlags(QGraphicsItem.ItemIsMovable | QGraphicsItem.ItemIsSelectable)

        self.setScene(self.scene)

        # Question 1
        print(self.scene.itemAt(110, 40, QTransform()))

        # Question 2
        self.scene.focusItemChanged.connect(self.my_slot)

    def my_slot(self, new_item, old_item):
        print(new_item)
        print(old_item)


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

Any help would be appreciated.


回答1:


1. what does QTransform() mean in itemAt()?

As it indicates the docs it is only necessary to pass the deviceTransform if there is an item that ignores the transformations, then how is it done so that an item does not support transformation? you must enable the flag Qt::ItemIgnoresTransformations.

With your code you can not see the difference so I have implemented the following example where there are 2 items one with the flag ItemIgnoresTransformations activated and the other not. Then when you press any of the items it is expected that the item will be printed in the console but you will see that the item that has the ItemIgnoresTransformations flag returns None if you pass QTransform (), if you press the radiobutton to pass the viewportTransform() you will see that Now both items are printed on the console. So you must pass the deviceTransform if there is any item with the flag ItemIgnoresTransformations enabled.

import sys
from PyQt5 import QtCore, QtGui, QtWidgets


class Demo(QtWidgets.QGraphicsView):
    def __init__(self):
        super(Demo, self).__init__()
        self._scene = QtWidgets.QGraphicsScene()
        self._scene.setSceneRect(0, 0, 300, 300)
        self.setScene(self._scene)
        self.rect1 = self._scene.addRect(
            100, 30, 100, 30, brush=QtGui.QBrush(QtGui.QColor("red"))
        )
        self.rect1.setFlag(QtWidgets.QGraphicsItem.ItemIgnoresTransformations)

        self.rect2 = self._scene.addRect(
            200, 30, 100, 30, brush=QtGui.QBrush(QtGui.QColor("green"))
        )

        self.rotate(50)
        self._use_deviceTransform = False

    def mousePressEvent(self, event):
        sp = self.mapToScene(event.pos())
        item = self._scene.itemAt(
            sp,
            self.viewportTransform()
            if self._use_deviceTransform
            else QtGui.QTransform(),
        )
        print(item)

    def set_use_deviceTransform(self, t):
        self._use_deviceTransform = t


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    radiobutton = QtWidgets.QRadioButton("use deviceTransform")
    demo = Demo()
    radiobutton.toggled.connect(demo.set_use_deviceTransform)
    w = QtWidgets.QWidget()
    lay = QtWidgets.QVBoxLayout(w)
    lay.addWidget(radiobutton)
    lay.addWidget(demo)
    w.show()
    w.resize(640, 480)
    sys.exit(app.exec_())

2. why focusItemChanged signal is not working?

The signal is triggered if the focus of an item changes, but by default the items have no focus so the signal is not emitted, the solution is to activate the flag QGraphicsItem::ItemIsFocusable:

import sys
from PyQt5.QtGui import QTransform
from PyQt5.QtWidgets import QApplication, QGraphicsItem, QGraphicsScene, QGraphicsView
from PyQt5.QtCore import pyqtSlot, Qt


class Demo(QGraphicsView):
    def __init__(self):
        super(Demo, self).__init__()
        self.resize(300, 300)

        self.scene = QGraphicsScene()
        self.scene.setSceneRect(0, 0, 300, 300)

        self.rect = self.scene.addRect(100, 30, 100, 30)
        self.ellipse = self.scene.addEllipse(100, 80, 50, 40)

        self.rect.setFlags(
            QGraphicsItem.ItemIsMovable
            | QGraphicsItem.ItemIsSelectable
            | QGraphicsItem.ItemIsFocusable
        )
        self.ellipse.setFlags(
            QGraphicsItem.ItemIsMovable
            | QGraphicsItem.ItemIsSelectable
            | QGraphicsItem.ItemIsFocusable
        )

        self.setScene(self.scene)
        self.scene.focusItemChanged.connect(self.my_slot)

    @pyqtSlot("QGraphicsItem*", "QGraphicsItem*", Qt.FocusReason)
    def my_slot(self, new_item, old_item, reason):
        print(old_item, new_item)


来源:https://stackoverflow.com/questions/55824951/pyqt5-questions-about-qgraphicsscenes-itemat-and-focusitemchanged

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