Russian Qt Forum
Апрель 19, 2024, 06:52 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: (РЕШЕНО) При первом рисовании сцены не работает mapToItem  (Прочитано 4657 раз)
Гурман
Гуру общения
******
Offline Offline

Сообщений: 1442

Qt 2.2, 3.3, 4.5, 4,7, 4.8, 5.3, 5.6, 5.9, 5.12


Просмотр профиля
« : Февраль 25, 2015, 16:50 »

Есть графический айтем, который привязан к другому графическому айтему, как к родителю, то есть, указатель на родителя выдаётся методом parentItem(). Обнаружил странный глюк - при первом рисовании сцены, если я вызываю
Код:
    qDebug() << mapToItem( parentItem(), QPointF(tipX,bodyY) ); // tipX,bodyY - координаты точки в системе суб-айтема
то получаю в консоли
Цитировать
QPointF(2.5, 4.33)
при этом tipX == 2.5 ,bodyY == 4.33, то есть, трансляция точки в координаты айтема не происходит

Но если очистить сцену, и нарисовать на ней всё тоже самое повторно, то
Цитировать
QPointF(-40, 20)
что и должно быть. Пытался до первого рисования очистить сцену, потом рисовать на ней - без разницы.

Полез в потроха Qt отладчиком, и обнаружил, что при выполнении mapToItem внутри производится проверка флага QTransform::m_dirty (очевидно, флаг наличия трансформации). Так вот при первом рисовании он 0, а при повторном 1. Существенно - необходимая трансформация выполняется всегда ПОСЛЕ того, как на схеме уже что-то нарисовано. На самом деле, сначала рисуются объекты схемы, потом соединения между объектами. При рисовании соединений возникает этот глюк. Разницы между первым и вторым рисованием в моём коде нет никакой. Объект класса QTransform - это тот самый, что возвращает метод QGraphicsItem::itemTransform(). Трансформация производится вызовом его QPointF QTransform::map(QPointF). И вот внутри этого метода в первый раз оказывается, что... никакой трансформации нет, и я вместо отображения получаю локальные координаты точки в суб-айтеме.

Совершенно не понятно, почему при первом вызове нет признака трансформации, а при втором - уже есть. И где этот признак взводится. Причем та же фигня при попытке сделать mapToScene(QPointF(tipX,bodyY)), что может быть объяснимо вызовом mapToItem(parentItem()...) внутри mapToScene() /*не лазил туда*/.

Между рисованием объектов сцены, и рисованием соединителей производится восстановление сохраненных в сцене масштабов отображения и позиции окна. Но они по идее не должны влиять, поскольку совершенно одинаково выполняются как при первом рисовании, так и при втором. ЗЫ: Как и ожидалось, отключение этих восстановлений ничего не даёт.

В общем, еще один глюк Qt, похожий на баг. В Инете ничего найти не удалось.
« Последнее редактирование: Февраль 26, 2015, 23:23 от Гурман » Записан

2^7-1 == 127, задумайтесь...
Гурман
Гуру общения
******
Offline Offline

Сообщений: 1442

Qt 2.2, 3.3, 4.5, 4,7, 4.8, 5.3, 5.6, 5.9, 5.12


Просмотр профиля
« Ответ #1 : Февраль 25, 2015, 18:59 »

Посмотрел, как работает mapToScene в этом случае (результат точно такой же, как у mapToItem - при первом вызове ). Там афинные преобразования, которые при первом рисовании не учитывают нужные смещения, а при втором уже учитывают.

Креатор из комплекта Qt 4.7, у него нет останова на изменении переменных, поймать где эти преобразования внутри Qt меняются не могу.
Записан

2^7-1 == 127, задумайтесь...
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #2 : Февраль 25, 2015, 19:13 »

В общем, еще один глюк Qt, похожий на баг.
Никогда не работал с QGraphicsScene, но все же: почему бы не компильнуть примерчик (один из идущих с Qt) и вставить туда строку печати? Если воспроизведется - ну кто ставит dirty я постараюсь найти (недавно было нечто подобное). Конечно подготовка измененного примера Ваша, даже не пытайтесь это кому-то "поручить"  Улыбающийся
Записан
Гурман
Гуру общения
******
Offline Offline

Сообщений: 1442

Qt 2.2, 3.3, 4.5, 4,7, 4.8, 5.3, 5.6, 5.9, 5.12


Просмотр профиля
« Ответ #3 : Февраль 25, 2015, 20:48 »

Да изменить то не проблема, проблема найти пример. Я как-то не особенно ориентируюсь в примерах Qt, последний раз их ковырял лет 5 назад. Это мне еще разбираться надо, какой пример подходящий.

Если недавно было нечто подобное - может вспомните хотя бы контекст, в котором это было? Ключевые слова, которые тогда упоминались?
« Последнее редактирование: Февраль 25, 2015, 21:03 от Гурман » Записан

2^7-1 == 127, задумайтесь...
Гурман
Гуру общения
******
Offline Offline

Сообщений: 1442

Qt 2.2, 3.3, 4.5, 4,7, 4.8, 5.3, 5.6, 5.9, 5.12


Просмотр профиля
« Ответ #4 : Февраль 25, 2015, 23:10 »

Перенес первое рисование из конструктора главного окна в метод, который вызывается по таймеру через 1 мс после завершения этого конструктора. mapToScene в этом месте стал работать правильно, но потом при последующих рисованиях лезут артефакты. Не отрисовываются кусками айтемы, линии. Такого вообще ни разу не было. Пока ничего не помогло, ни update(), ни сбрасывание кэша QGraphicsView, ни invalidate() сцены. В какой-то такой глюкоген попал, что пока не ясно куда копать.

ЗЫ: от артефактов я избавился, установив gw->setViewportUpdateMode( QGraphicsView::FullViewportUpdate ); но... при этом опять перестал работать mapToScene.
« Последнее редактирование: Февраль 25, 2015, 23:33 от Гурман » Записан

2^7-1 == 127, задумайтесь...
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #5 : Февраль 26, 2015, 11:27 »

Да изменить то не проблема, проблема найти пример. Я как-то не особенно ориентируюсь в примерах Qt, последний раз их ковырял лет 5 назад. Это мне еще разбираться надо, какой пример подходящий.
Открываем фолдер Examples. Ищем файлы содержащие QGraphicsScene. Ага, они в фолдере graphicsview. Выбираем пример - ну вот diagramscene (наугад). Смотрим есть ли там QGraphicsItem - есть. Ну а дальше Вам и карты в руки.

Важно проверить является ли найденный Вами баг общим или же связан с конкретным проектом. Дальше могут появиться мысли. Это стоит небольшой возни с примером.

Если недавно было нечто подобное - может вспомните хотя бы контекст, в котором это было? Ключевые слова, которые тогда упоминались?
Я имею ввиду недавний случай с "ложной перерисовкой" (найти что ее вызывает)
Записан
Гурман
Гуру общения
******
Offline Offline

Сообщений: 1442

Qt 2.2, 3.3, 4.5, 4,7, 4.8, 5.3, 5.6, 5.9, 5.12


Просмотр профиля
« Ответ #6 : Февраль 26, 2015, 14:15 »

Это не толковый вариант действий. Там сто пудов проекты не совпадают с моим, может быть куча нюансов. Поэтому я сделал по-другому - создал с 0 "лабораторный" проект, который в проблемной части по структуре совпадает с моим. Только меньше его, примерно как детский шалаш меньше башни Россия в Москва-сити, всего 150 строк.

И сразу получил глюк - первый же вызов mapToItem внутри айтема-наследника, при попытке пересчитать его локальные координаты в координаты айтема-родителя вернул мне... увы... те же локальные координаты наследника.  Обеспокоенный

Теперь надо как-то мочалить айтемы, сцену, чтобы добиться возврата действительно пересчитанных координат. В основном моём проекте достаточно сделать драг-дроп любого айтема сцены, чтобы mapToItem в ней заработал правильно. То есть, первый раз соединения между айтемами нарисованы неверно, но буквально достаточно дернуть любой айтем мышью - и всё, после этого все соединения будут рисоваться верно. Очевидно, проходит какая-то инициализация трансформеров сцены, которой нет изначально. Это явно баг.

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

Лабораторный проект могу дать для проверки в более новых версиях Qt. Может оказаться, что там баг исправлен. Сам их ставить и проверять не буду - не до того. Из-за этого бага застряла реализация сложной и необходимой функциональности - ортогональных соединителей между айтемами.
Записан

2^7-1 == 127, задумайтесь...
Гурман
Гуру общения
******
Offline Offline

Сообщений: 1442

Qt 2.2, 3.3, 4.5, 4,7, 4.8, 5.3, 5.6, 5.9, 5.12


Просмотр профиля
« Ответ #7 : Февраль 26, 2015, 22:30 »

Всё, проблема найдена. Я не в том месте, где надо, устанавливал позицию субайтема. В результате получалось, что рисовало всё правильно, и даже правильные координаты потом возвращало, но относительные координаты считало не правильно. Вызов setPos() для установки координат субайтема в системе координат родителя должен быть обязательно до того, как Qt первый раз вызовет boundingRect() или paint() при привязке айтема к сцене.
« Последнее редактирование: Февраль 26, 2015, 23:24 от Гурман » Записан

2^7-1 == 127, задумайтесь...
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.054 секунд. Запросов: 22.