Вопрос по QGraphicsScene и QGraphicsView – перерисовка объектов
qgraphicsscene, QGraphicsView, QHash, QMap, Qt
Доброго вам времени суток,
Работая с QGraphicsScene, возникает необходимость отображать большое количество однотипных элементов (item’ов) – порядка миллионов квадратов (rectangle’ов 7х7 ). Их прорисовка(scene->addRect) и удаление(scene->removeItem) занимает слишком большое кол-во времени, а она происходит периодически, скажем 0,3 сек . Вопрос, как можно было бы это оптимизировать?
У меня есть мысль прорисовывать только те, что находятся в видимой части сцены. Ну может с каким-то запасом. А передвигаясь в “новые области” дорисовывать оставшиеся. Проблема как узнать координаты видимой части QGraphicsScene или QGraphicsView ?
Если у вас есть другие мысли по поводу оптимизации этой задачи, буду рад услышать.
Работая с QGraphicsScene, возникает необходимость отображать большое количество однотипных элементов (item’ов) – порядка миллионов квадратов (rectangle’ов 7х7 ). Их прорисовка(scene->addRect) и удаление(scene->removeItem) занимает слишком большое кол-во времени, а она происходит периодически, скажем 0,3 сек . Вопрос, как можно было бы это оптимизировать?
У меня есть мысль прорисовывать только те, что находятся в видимой части сцены. Ну может с каким-то запасом. А передвигаясь в “новые области” дорисовывать оставшиеся. Проблема как узнать координаты видимой части QGraphicsScene или QGraphicsView ?
Если у вас есть другие мысли по поводу оптимизации этой задачи, буду рад услышать.
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.Ол саған ұнайды ма? Әлеуметтік желілерде бөлісіңіз!
Пікірлер
OI
- Ora Iro
- Жел. 24, 2024, 6:38 Т.Ж.
C++ - Тест 001. Первая программа и типы данных
- Нәтиже:40ұпай,
- Бағалау ұпайлары-8
AD
- Akiv Doros
- Қар. 11, 2024, 2:58 Т.Қ.
C++ - Тест 004. Указатели, Массивы и Циклы
- Нәтиже:50ұпай,
- Бағалау ұпайлары-4
m
- molni99
- Қаз. 26, 2024, 1:37 Т.Ж.
C++ - Тест 004. Указатели, Массивы и Циклы
- Нәтиже:80ұпай,
- Бағалау ұпайлары4
Соңғы пікірлер
ИМ
Django - Оқулық 017. Теңшелген Django кіру беті Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
Игорь МаксимовҚар. 22, 2024, 11:51 Т.Ж.
Evgenii LegotckoiҚаз. 31, 2024, 2:37 Т.Қ.
Qt Creator көмегімен fb3 файл оқу құралы Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
ИМ
Django - Сабақ 064. Python Markdown кеңейтімін қалай жазуға болады Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
Игорь МаксимовҚаз. 5, 2024, 7:51 Т.Ж.
QML - Сабақ 016. SQLite деректер қоры және онымен QML Qt-та жұмыс істеу Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
Енді форумда талқылаңыз
Evgenii LegotckoiМаусым 24, 2024, 3:11 Т.Қ.
t
google domain [url=https://google.com/]domain[/url] domain [http://www.example.com link title]
tonypeachey1Қар. 15, 2024, 6:04 Т.Ж.
NSProjectМаусым 4, 2022, 3:49 Т.Ж.
IscanderCheҚаз. 31, 2024, 3:43 Т.Қ.
Машина тьюринга // Начальное состояние 0 0, ,<,1 // Переход в состояние 1 при пустом символе 0,0,>,0 // Остаемся в состоянии 0, двигаясь вправо при встрече 0 0,1,>…
Добавление и удаление элементов в принципе довольно дорогостоящий процесс при таком раскладе будет. Нужно действительно оптимизировать эту часть. Но у меня вопрос: “А зачем это сделано именно таким образом? Для чего удалять и добавлять элементы для обновления? Если я правильно понял, то здесь происходит периодическое удаление всех элементов с графической сцены их создание и добавление на графическую сцену. Может лучше проверять объекты на предмет того, а стоит ли удалять эти объекты, если они там должны остаться”
А определить, какая часть графической сцены видна в данный момент можно следующим образом:
В данном случае будет возвращён объект QPolygonF, который будет представлять собой прямоугольник, четыре вершины которого будут представлены в координатах графической сцены. Ну а потом можно определить, какие из item`ом лежат внутри этой области и уже работать с ними.
Сейчас у меня три следующих вопроса:
1) Какой слот/сигнал необходимо использовать чтобы следить за изменением размера и/или координат (двигаясь при помощи слайд баров) scene, чтобы потом выводить изображение в нужную часть окна?
2) При помощи какого параметра можно остановить все изменения(добавления и удаления) на scene, если изменяется ее размер или происходит движение(при помощи слайдбара)?
2)
ui->graphicsView->mapToScene(QRect(0, 0,
ui->graphicsView->viewport()->width(),
ui->graphicsView->viewport()->height()));
при запуске программы почему-то инициализируется каким-то произвольным размером 0,0:98,28, хотя и размеры окна и scene уже заданы, да и сделав проверку на запущенной программе получаю -300,-200 : 300,200. Конечно истинные значения можно ручками вбить, но хотелось бы разобраться.
П.С. Спасибо за новый урок по QThread, жду продолжения. Буду свои основные вычисления разделять на потоки по количеству ядер процессора, для ускорения вычислений.
Не код, а задача. в зависимости от нее можно предложить патерны для оптимизации. возможно частично или вообще отказаться от qt graphics классов.
задача заключается в следующем: необходимо довольно быстро(в секунду 2-10 раз) добавлять и убирать большое количество одинаковых квадратиков(желательно миллион) с очень большого поля (что-вроде игры жизнь). На QGraphicsScene addRect и removeItem идут довольно долго, поэтому приходится исхитрятся- добавлять только на видимую часть сцены. Если предложите что-то более быстрое и оптимальное буду очень благодарен.
Можно использовать сигнал изменения позиции скроллбаров.
А вот здесь уже не в параметре дело, а в том, какой Вы для этого алгоритм напишите. У вас же этот процесс связан, наверняка, с каким-нибудь таймером или иным флагом по работе с игровым объектами. Вот по нему и стартуйте, и останавливайте работу программы. Как вариант, могу предложить посмотреть цикл статей на тему написания простой игры. Смотрите ту часть кода, где идёт работа с игровым таймером.
P/S/ по QThread была самая базовая статья. Это не самый кошерный способ по работе с потоками, поскольку правильнее его использовать для расширения функционала класса. Чуть позже будут ещё статьи на эту тему.
Этот принцип мне понятен. Вы правильно предположили, что здесь имеет место таймер, но изменение на сцене будут происходить в каком-то “долгом” цикле, где:
1)Необходимо мониторить какой-то параметр изменения размера/положения сцены, вопрос какой это мог бы быть параметр?
2)Как быть если получен положительный результат этого параметра(происходят изменения сцены), как остановить “долгий” цикл и продолжить его после стабилизации сцены?
Так я же уже ответил примером кода. В том примере отслеживаются скроллбары, изменение положение графической сцены в graphicsView как раз и можно отслеживать теми слотами. Изменение размера графической сцены можно отслеживать по изменению размера окна, допустим.
Ну вот здесь вопрос поинтереснее получается. Я пока даже не знаю, как бы я это сделал. Возможно, послать сигнал на остановку процесса пересчёта квадратиков. Дать завершиться текущей итерации цикла, а потом перерисовать сцену. Кстати, сам расчёт квадратиков имеет смысл делать на какой-нибудь матрице, которая будет транслироваться на графическую сцену. Я не смотрел алгоритм той игры, но полагаю, что примерно так это и происходит там.
1) Добавлять и удалять на графической сцене только те итемы, которые находятся в видимой части;
2) Не пересоздавать те итемы, которые остались на месте в текущей итерации после предыдущей итерации;
3) Посмотреть в сторону OpenGL – это может помочь увеличить производительность.
В данный момент над этим работаю, но есть сложности из-за выбранного мною алгоритм (для того чтобы отобразить и убрать клетки в новой части окна придется перебрать всю хеш таблицу живых клеток)
Этот совет уже применен.
Видимо придется пробовать, но к сожалению пока не нашел “подходящих” примеров, а если использовать те что есть, придется переделывать весь интерфейс программы.
Боюсь что матрица не очень подходит. При размерах поля, например 1000 000 на 1000 000 придется работать с ~100GB массивом. Я применил другой метод, который не зависит от величины поля, а только от количества “живых” клеток на нем.(если интересно код прилагается). При малом количестве клеток все ОК, но при большом затягивается их добавление и стирание, что тормозит программу. А также проявляется странный эффект если подвигать скрол вверх-вниз, не удаляются некоторые пиксели.
Вот это и проблема, можно ввести какую-нибудь bool переменную, которая останавливала бы изменения на сцене, но как ею управлять? Включить можно при помощи подсказанных вами слотов или по изменению окна, но как выключить? (Хотя интуиция мне подсказывает что должен быть какой-нибудь параметр для QGraphicsScene или View останавливающий изменения на сцене при внешних манипуляциях)
gameoflife_new.zip
А Вы случаем не пробовали запускать в режиме Выпуска, а не Отладки? Скорость сама по себе достаточно неплохо у приложения возрастает. Для начала так проверили бы. Также подтормаживают работу приложения всякие qDebug().
Я так понял из приложения, что хеш таблица не сортированная получается. Жаль. Так бы можно было просто поиском с половинным делением находить крайние точки в хеш таблице и перебирать уже только нужную область.
Ну да. Что-то я лиханул.
У Вас же таймер есть в программе. Его и останавливайте на время обработки изменения размеров. А что касается артефактов, то, по моему, это и не артефакты, а неправильно создавшиеся item’ы что ли. scene->update() просто их не убирает, хотя обычно это позволяет удалить артефакты. Видимо, это item`ы создавшиеся некорректно при передвижении сцены. Таким образом, их координаты центральные отличаются от тех, что имеются в хеш таблице, поэтому и не получается их удалить. Они просто становятся не отслеживаемыми.
Вы совершенно правы, но так как это учебный проект, то требуется отработать все возможные улучшения.
А вот это уже интересно. Разве всякие хеш таблицы и мапы при своем заполнении сразу не упорядочиваются? Насколько я понимаю именно это свойство и является их отличием от векторов, списков(list) и т.п.. И разве в них для этих целей в них специально не созданы функции вроде contains и find, которые производят быстрый поиск, и неужели им нужна дополнительная сортировка? Если да, то походу я лоханулся. Тогда получается лучше работать с каким-нибудь вектором или вообще простым динамическим массивом, только перед писком сортировать или лучше пробовать хеш сортировать, как вы считаете? (Кстати, посмотрел описание- там пишут что хеш произволен, а мап упорядочен. Однако у меня с хешем вычисления быстрее шли, странно).
Но ведь таймер запускает “долгие” функции добавления и удаления и если я его остановлю они-то не остановятся. Мне кажется, что останавливать необходимо именно эти функции. Только я ни как не могу придумать как это реализовать. Есть идея создать напр. переменную bool stopChanges которая получала true при (…->verticalScrollBar(), &QScrollBar::valueChanged) и останавливала бы эти функции (можно и таймер), но как ее вернуть в false, когда уже будет можно включить остановленные функции?
Очень похоже что здесь вы, как всегда, правы, я думаю это еще один мотив использовать остановку изменений на сцене при ее движении.
Не было возможности подробно вдаваться в особенности QHash и QMap, но тоже глянул документацию. Да, QMap в отличие от QHash сортируется. Но в той же документации сказано, что QHash быстрее в плане поиска. Там иной алгоритм применяется. Так что, похоже, что ничего странного в этом нет.
Можно попробовать использовать QMap вместо QHash, но с одним нюансом. Поскольку QMap сортируется по ключу (в данном случае это будет скорее всего X координата), то использовать граничные координаты видимой области, чтобы не перебирать весь QMap. То есть нашли координату первой линии, и прошлись итератором до конца этой линии, вместо того, чтобы делать поиск find/contains каждого объекта, а потом нашли координату второй линии и т.д. до последней линии. Возможно, получится выиграть некоторые ресурсы по времени.
Тогда что-то наподобие выполнения этих функций в отдельном потоке и управление методом, в котором они выполняются через эту самую переменную. Чуть позже я выложу статью такого подхода к потокам.
А альтернативное решение не подскажите? ни как не могу остановить изменения на сцене.
Могу предложить глянуть новую статью по потокам в Qt приложении. Посмотрите внимательно на использование переменной m_running. Думаю, что примерно таким же образом Вам нужно будет выскакивать из цикла в Ваших долгих функциях, не дожидаясь отрисовки оставшихся объектов.
Спасибо за урок по потокам. Что-то вроде переменной m_running я и собираюсь использовать. Только у меня опять не разрешенная задача, я знаю как включить(true) ее в начале перед запуском потока (при нажатии кнопки или при запуске програмы), знаю как ее выключить(false) (…->verticalScrollBar(), &QScrollBar::valueChanged) и остановить поток, но как продолжить поток когда сцена стабилизируется? Не нажимать же для этого Старт кнопку каждый раз когда поскролю сцену. Ни как не могу придумать условие или найти слот, чтобы ее автоматически включить (m_running=true);
Я очень извиняюсь, но у меня ни как не получается воплотить вышеуказанный вами код. Постоянно кидает ошибку:
C:\…\mainwindow.cpp:33: error: no matching function for call to ‘MainWindow::connect(QScrollBar*, const char*, MainWindow*, const char*)’
connect(ui->graphicsView->horizontalScrollBar(),SIGNAL(&QScrollBar::valueChanged()),this ,SLOT(&MainWindow::scrollSlot()));
Что-то не так с ui->graphicsView->horizontalScrollBar() и его сигналом. Я перепробовал все возможные варианты этой записи, но ни как. Не подскажите? Со scrollSlot() все в порядке, другими сигналами он прекрасно запускается. К стати я кажется придумал как мне выкрутиться с остановкой и запуском сцены: QScrollBar вместе с valueChanged() наследует sliderPresssed() и sliderReleased(). Если получиться с первым, то должно и с другими, но пока что ни как не получается.
П.С. разобрался с “артефактами” образующимися при движении окна. graphicsView имеет свойство viewportUpdateMode::BoundinrRectViewportUpdate с помощью его параметров такие вещи как раз устраняются.
Во-первых, удостоверьтесь, что на месте строка
#include <QScrollBar>
Во-вторых, очистить полностью проект от последней сборки, лучше вообще удалить папку build. Смахивает на то, что таблица сигналов и слотов не полная. Запуск qmake может и не помочь. Так что удалить build и пересобрать заново.
Даже не представляю каким еще образом можно отобразить много “квадратиков” на большом поле в Qt.
Спасибо помогло, а я перелопатил всю документацию по QScrollBar. Видимо я сегодня заработался.
увеличиваешь масштаб вьюпорта в 7 раз
рисуешь
OpenGL )))
Я бы сам им позанимался, но пока нет желания, поскольку других дел валом, и нужно иногда отдыхать от Qt.
Вообще, я до конца не был уверен, что это поможет, потому что обычно другую ошибку в этом случае выдаёт.
QPainter вполне может справить
Я думал о QPainter е, но не нашел нормальных примеров: как его вставить в graphicsVew, как настроить взаимодействие с мышкой. Без примеров трудновато.
К сожалению, эта информация мне пока еще ни чего не говорит.
Исходя из того насколько я понял задачу.
вот пример отображение 1 000 000 обьектов, совершенно без оптимизации.
считаю что нужно смотреть в эту сторону, если по_работать с оптимизацией, можно обработать уйму сложных обьектов (с анимацией и логикой) при условии создания своей сцены которая будет обрабатывать обьекты в потоках (преимущество только для многоядерных cpy)
если лень писать свою обработку. можно использовать Qt сцену немного поработав с View интегрировав туда масштабирование – будет быстро но не гибко.
Может через пару часиков попробую смастерить что то подобное.
Заранее извиняюсь если где то ошибся потому что не читал весь пост.
scrollbarwidget.zip
Ну может и без оптимизации, но в качестве вывода используется OpenGL.
Я про строку
setViewport(new QGLWidget(this));
1) как построить взаимодействие с мышью, чтобы при нажатии на поле появлялся или исчезал “квадратик”?
2) да и интерфейс, блин, не ясно как закинуть.
А QPainter только на виджетах рисует или им можно и в graphicsView? А то мне сейчас с интерфейсом чуть не понятно.