Модераторы: Daevaorn
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> QGraphicsScene: рекреат, лучший вариант 
V
    Опции темы
Любитель
Дата 12.12.2006, 18:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Программист-романтик
****


Профиль
Группа: Комодератор
Сообщений: 3645
Регистрация: 21.5.2005
Где: Воронеж

Репутация: 24
Всего: 92



Упрощенно говоря имеем в классе некоторого виджета графикс-вью (graphicsView_) и прайват-функцию createScene, которая заполняет сцену всякой ерундой. В числе прочего там есть кнопочка, щелчок по которой должен вызщвать пересоздание сцены. Кнопка (отдельный класс график-итемов) обрабатывает нажатие/отпуск мыхи и т. д.

Вариант 1: просто создаём новую сцену и устанавливаем её во вью. Работает. Но память всех сцен освобождается только после разрушение рассматриваемого виджета (он выступает парентом для сцен). Впрочем сие логично, но затратно.

Вариант 2: что-то такое:
Код

QGraphicsScene* oldScene = graphicsView_->scene();
QGraphicsScene* newScene = new QGraphicsScene(this);
graphicsView_->setScene(newScene);
oldScene->SetParent(0);
delete oldScene;
createScene(); // берёт текущую сцену

Сие не работает. Точнее, работает, если рекреат сцены инициируется внешним способом, но не кликом по кнопке сцены. После mouseReleasedEvent куте инициирует хаувер-события (точно не смотрел что именно). Причём даже когда на сцене нет ни одного итема, аксептющего хауверы (по видимому этот аксепт работает как обычный ивент-филтер). Так как сцены к тому моменту не существует, то this сцены получается не валидный. В итоге получаем вылет.

Вариант 3: типа такого:
Код

// делитим все итемы сцены
for (;;)
{
   QList<QGraphicsItem*> items = graphicsView_->scene()->items();
   if (items.isEmpty())
      break;
   graphicsView_->scene()->removeItem(items.first());
   delete items.first();
}

createScene();

Сие работает. Но:
1. Не красиво выглядит. Почему я не нашёл у сцены методов вроде rest, removeAllItems или clear (или ночью глаза плохо видят в асистенете?) ???
2. Память (по таск-менеджеру) после рекреата сцены все равно прибавляется. На 4-5 рекреатах - ничего, а потом потихоньку начинает тормозить (память идёт под 100 мегабайт). Правда, там ещё тупанул в одном месте (дома исправлю) - пиксмэпы на кнопках создаются каждый раз заново (на сцене много кнопок с одной картинкой). Пожалуй, надо статик-мембер завести. Насколько я помню, копирование QPixmap ведёт к shared-доступу. Но всё же к увеличению используемой памяти это не должно вести (кол-во кнопок старой и новой сцены всегда почти совпадает).

Как лучше всего рекреатить сцену? Ваши мнения?


--------------------
PM MAIL ICQ Skype   Вверх
JackYF
Дата 12.12.2006, 18:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


полуавантюрист
****


Профиль
Группа: Участник
Сообщений: 5814
Регистрация: 28.8.2004
Где: страна тысячи озё р

Репутация: 18
Всего: 162



Вариант 3, завернутый в отдельную функцию и сделанный while' ом:
Код

QList<QGraphicsItem*> items = graphicsView_->scene()->items();
while ( ! items.isEmpty() )
{
   graphicsView_->scene()->removeItem(items.first());
   delete items.first();
}
createScene();



--------------------
Пожаловаться на меня как модератора можно здесь.
PM MAIL Jabber   Вверх
Любитель
Дата 14.12.2006, 18:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Программист-романтик
****


Профиль
Группа: Комодератор
Сообщений: 3645
Регистрация: 21.5.2005
Где: Воронеж

Репутация: 24
Всего: 92



JackYF, сие не сработает - ты получишь вечный цикл (ты не удаляешь элемент из списка).

Что касается отдельной функции - это и есть recreateScene().

Оставил последний вариант, ошибка оказалась в другом. Когда я писал createScene, я считал, что сцена новая и коннектил некоторые сигнал/слоты (в том числе рекреат). Я просто упростил здесь задачу (в принципе на кнопках висят более масштабные действия, некоторые из которых в некоторых случаях вызывают сигнал, на который законнектен рекреат). Короче, в итоге на один мой класс, коннектилось при рекреате слот этого же рекреата. В итоге с каждым рекреатом росло кол-во его вызовов при следующем клике по кнопке.

Проверив, сию ситуацию от ошибки избавился (память по-видимому шла под хранение коннектов и прочие кутешные вещи - сейчас всё чисто).


--------------------
PM MAIL ICQ Skype   Вверх
zabivator
Дата 14.12.2006, 18:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 171
Регистрация: 7.6.2006
Где: нск

Репутация: 1
Всего: 2



Любитель, вот за это плюс поставить можно! Вдохновил!
--------------------
#include <zabivator>int main( int, char * [] ){   while( Zabivator::жив() ) Zabivator::моск()++;   return 0;}
PM MAIL WWW ICQ   Вверх
Любитель
Дата 14.12.2006, 18:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Программист-романтик
****


Профиль
Группа: Комодератор
Сообщений: 3645
Регистрация: 21.5.2005
Где: Воронеж

Репутация: 24
Всего: 92



Начинаем флуд.

Честно - не понял чем (хотя б в каком посте).


--------------------
PM MAIL ICQ Skype   Вверх
zabivator
Дата 14.12.2006, 18:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 171
Регистрация: 7.6.2006
Где: нск

Репутация: 1
Всего: 2



Любитель,  QGraphicsScene - видел столько раз эту шнягу в ассистансе. Но когда сейчас увидел код в его использованием... прозрел, что это ведь на самом деле очень-очень вкусно!
--------------------
#include <zabivator>int main( int, char * [] ){   while( Zabivator::жив() ) Zabivator::моск()++;   return 0;}
PM MAIL WWW ICQ   Вверх
Любитель
Дата 15.12.2006, 11:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Программист-романтик
****


Профиль
Группа: Комодератор
Сообщений: 3645
Регистрация: 21.5.2005
Где: Воронеж

Репутация: 24
Всего: 92



Да, кстати, вариант с непереприсваиванием списка итемов (при рекреате) не прокатит и в модифицированном варианте. Когда мы будем удалять первый элемент из списка (для списка это достаточно эффективно) или итерировать по нему (вместо условия isEmpty). Точнее в исключительных случаях это сработает, но в большинстве (в т. ч. у меня) - нет.

Почему? Объясняю. В куте кругом используется простая концепция парентов, реализованная на уровне QObject. Деструктор парента удаляет все свои child-итема. QGRaphicsItem не является наследником QObject, но там реализуется подобная вещь. У итема есть сцена к которой он относится и есть парентовый график-итем. Последний может быть нулевым указателем. В этом случае итем делитит сцена. Метод items вернёт все итемы. В итоге мы можем долбануть родителя, его дети тоже подохнут, но указатели на них (уже невалидные) останутся. Мы будем долбать и их. Сие вызовет вылет. Посему останавливаюсь на прошлом варианте.

Правда, что тупанул - явно удалял элемент из сцены. С этим прекрасно справляется его деструктор.

Если не нравиться выход посередине. Можно просто искуственно размножить начало цикла (благо оно в одну строчку):
Код

QList<QGraphicsItem*> items = graphicsView_->scene()->items();
while (!items.isEmpty())
{
   delete items.first();
   items = graphicsView_->scene()->items();
}


Пожалуй этот вариант даже эстетичней. Даже в чистом виде потерь между двойным написанием кода почти нет. 90% компилер в состоянии скомпилировать сие с фактическим выходом посередине.


--------------------
PM MAIL ICQ Skype   Вверх
Любитель
Дата 15.12.2006, 11:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Программист-романтик
****


Профиль
Группа: Комодератор
Сообщений: 3645
Регистрация: 21.5.2005
Где: Воронеж

Репутация: 24
Всего: 92



Вопрос решён.


--------------------
PM MAIL ICQ Skype   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0709 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.