Куда отправляется перевод QGraphicsItemGroup после его уничтожения? - PullRequest
1 голос
/ 05 марта 2020

У меня есть QGraphicsItem объекты в сцене, которые я совместно перемещаю, используя QGraphicsItemGroup, согласно этому ответу .

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

Я сделал небольшой пример, где прямоугольник отображается, затем масштабируется и переводится после пауз в 5 секунд. Преобразования объекта отображаются после каждого шага.

from PyQt5.QtCore import Qt, QThread
from PyQt5.QtGui import QTransform
from PyQt5.QtWidgets import QApplication, QGraphicsRectItem, QGraphicsScene, QGraphicsView, QMainWindow
import sys
import time


def print_transforms(obj):
  t = obj.transform()
  print(t.m11(), t.m12(), t.m13(), t.m21(), t.m22(), t.m23(), t.m31(), t.m32(), t.m33(), t.dx(), t.dy())
  assert len(obj.transformations()) == 0
  print(obj.rotation(), obj.scale())


class Thread(QThread):

  def run(self):
    print('initial transforms')
    print_transforms(rect)
    time.sleep(5)

    group = scene.createItemGroup([rect])
    group.setTransform(QTransform().scale(1.5, 1.5))
    scene.destroyItemGroup(group)
    print('after scaling')
    print_transforms(rect)
    time.sleep(5)

    group = scene.createItemGroup([rect])
    group.setTransform(QTransform().translate(100., 100.))
    scene.destroyItemGroup(group)
    print('after translation')
    print_transforms(rect)
    time.sleep(5)


app = QApplication([])
window = QMainWindow()
window.setGeometry(100, 100, 400, 400)
view = QGraphicsView()
scene = QGraphicsScene()
view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

rect = QGraphicsRectItem(0, 0, 150, 150)
scene.addItem(rect)

view.setScene(scene)
window.setCentralWidget(view)
window.show()
thread = Thread()
thread.finished.connect(app.exit)
thread.start()
sys.exit(app.exec_())

Он печатает следующее:

initial transforms
1.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 1.0 0.0 0.0
0.0 1.0
after scaling
1.5 0.0 0.0 0.0 1.5 0.0 0.0 0.0 1.0 0.0 0.0
0.0 1.0
after translation
1.5 0.0 0.0 0.0 1.5 0.0 0.0 0.0 1.0 0.0 0.0
0.0 1.0

Итак, мы начинаем с матрицы преобразования идентификаторов, а после масштабирования она изменяется на масштабирование матриц для удержания коэффициента масштабирования.

Однако после перевода матрица преобразования не изменяется, несмотря на то, что прямоугольник действительно сместился.

Поэтому мой вопрос: где перевод группы отправлен после того, как он был уничтожен?

1 Ответ

1 голос
/ 05 марта 2020

Прежде всего, не используйте QThread + sleep для задержки, так как у вас могут быть странные поведения, Qt предупреждает вас, указывая на предупреждение на консоли:

initial transforms
1.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 1.0 0.0 0.0
0.0 1.0
<b>QObject::startTimer: Timers cannot be started from another thread
QObject::startTimer: Timers cannot be started from another thread</b>
after scaling
1.5 0.0 0.0 0.0 1.5 0.0 0.0 0.0 1.0 0.0 0.0
0.0 1.0
<b>QObject::startTimer: Timers cannot be started from another thread
QObject::startTimer: Timers cannot be started from another thread</b>
after translation
1.5 0.0 0.0 0.0 1.5 0.0 0.0 0.0 1.0 0.0 0.0
0.0 1.0

Вместо этого используйте QTimer.


Переходя к задаче, давайте проанализируем положение элемента по мере применения изменений:

from PyQt5.QtCore import Qt, QObject, QTimer
from PyQt5.QtGui import QTransform
from PyQt5.QtWidgets import (
    QApplication,
    QGraphicsRectItem,
    QGraphicsScene,
    QGraphicsView,
    QMainWindow,
)
import sys


def print_transforms(obj):
    t = obj.transform()
    print(
        t.m11(),
        t.m12(),
        t.m13(),
        t.m21(),
        t.m22(),
        t.m23(),
        t.m31(),
        t.m32(),
        t.m33(),
        t.dx(),
        t.dy(),
    )
    assert len(obj.transformations()) == 0
    print(obj.rotation(), obj.scale())


class Test(QObject):
    def initial(self):
        print(rect.pos())
        print("initial transforms")
        print_transforms(rect)
        QTimer.singleShot(5000, self.scaling)

    def scaling(self):
        print(rect.pos())
        group = scene.createItemGroup([rect])
        group.setTransform(QTransform().scale(1.5, 1.5))
        scene.destroyItemGroup(group)
        print("after scaling")
        print_transforms(rect)
        QTimer.singleShot(5000, self.translation)
        print(rect.pos())

    def translation(self):
        print(rect.pos())

        group = scene.createItemGroup([rect])
        group.setTransform(QTransform().translate(100.0, 100.0))
        print(rect.pos())
        scene.destroyItemGroup(group)
        print("after translation")
        print_transforms(rect)

        print(rect.pos())

        QTimer.singleShot(1000, QApplication.quit)


if __name__ == "__main__":

    app = QApplication([])
    window = QMainWindow()
    window.setGeometry(100, 100, 400, 400)
    view = QGraphicsView()
    scene = QGraphicsScene()
    view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
    view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

    rect = QGraphicsRectItem(0, 0, 150, 150)
    scene.addItem(rect)

    view.setScene(scene)
    window.setCentralWidget(view)
    window.show()
    test = Test()
    test.initial()
    sys.exit(app.exec_())

И вы получите следующее:

PyQt5.QtCore.QPointF()
initial transforms
1.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 1.0 0.0 0.0
0.0 1.0
PyQt5.QtCore.QPointF()
after scaling
1.5 0.0 0.0 0.0 1.5 0.0 0.0 0.0 1.0 0.0 0.0
0.0 1.0
PyQt5.QtCore.QPointF()
PyQt5.QtCore.QPointF()
PyQt5.QtCore.QPointF()
after translation
1.5 0.0 0.0 0.0 1.5 0.0 0.0 0.0 1.0 0.0 0.0
0.0 1.0
PyQt5.QtCore.QPointF(100.0, 100.0)

Где видно, что перевод применяется к позиции элемента, а не к QTransform, поскольку при использовании destroyItemGroup() это означает:

void QGraphicsScene :: destroyItemGroup ( QGraphicsItemGroup * group)

Переопределяет все элементы в группе в родительский элемент группы, затем удаляет группу со сцены и, наконец, удаляет ее. Позиции и трансформации предметов отображаются из группы в родительскую группу.

(выделено мной)

В заключение: Когда группа уничтожается, все преобразования передаются элементам, кроме перевода, поскольку элемент перемещается с помощью setPos.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...