Russian Qt Forum

Программирование => Общий => Тема начата: Igors от Сентябрь 29, 2010, 19:16



Название: Временно блокировать рисование объекта
Отправлено: Igors от Сентябрь 29, 2010, 19:16
Добрый вечер

Извиняюсь за явно неудачное название темы. Есть массив данных, каждый элемент довольно сложная структура. Элементы могут рисоваться во многих окнах и очень по-всякому. В какой-то момент получена команда: (пере) создать один из элементов. Это модальный процесс, но все же окна обновлять надо (напр переключились на др. задачу и обратно). Проблема в том что когда идет процесс создания элемента - рисовать его нельзя, нужные данные отсутствуют, вылетаем.

Понятно что решение не одно. Напр. можно завести для элемента флажок locked и если взведен - не рисуем. Но мне это не очень нравится - придется вставлять эту проверку во все (разнообразные) рисования. Какие есть еще возможности?

Спасибо


Название: Re: Временно блокировать рисование объекта
Отправлено: Akon от Сентябрь 29, 2010, 22:06
Не совсем понятна проблема.

Элемент данных изменился/создался/удалился - бросается сигнал, в окнах слоты и далее обновление окон.

Что за специфика?


Название: Re: Временно блокировать рисование объекта
Отправлено: Igors от Сентябрь 29, 2010, 23:16
Не совсем понятна проблема.

Элемент данных изменился/создался/удалился - бросается сигнал, в окнах слоты и далее обновление окон.

Что за специфика?
Изменение может занимать несколько минут. В это время пользователю запрещается что-то нажимать (кроме кнопки Cancel), но отрисовывать окна все равно надо


Название: Re: Временно блокировать рисование объекта
Отправлено: Akon от Сентябрь 30, 2010, 10:38
Я так понимаю, что когда приходит время рисовать окно, объект данных может находится в незавершенном состоянии (длится несколько минут) и рисовать его нельзя.

Можно в объекте данных генерировать события:

Код:
Q_SIGNALS:
void updating();   // перед обновлением
void duringUpdate(); // в процессе обновления несколько раз
void updated(); // после обновления

Соответственно:
updating() - рисуешь что-то типа "Ждите..." (как правило, напрямую через QWidget::repaint());
duringUpdate() - если все в главном потоке, то обрабатываешь сообщения (QCoreApplication::ProcessEvents()), чтобы была возможность нажать на кнопку Cancel; также можешь выводить процент выполнения;
updated() - вожделенная отрисовка.


Название: Re: Временно блокировать рисование объекта
Отправлено: navrocky от Сентябрь 30, 2010, 13:07
Можно менять долго копию объекта, а в конце по ОК быстро вставить в основную структуру...

Наверное, правильного решения здесь нет, все зависит от трудозатрат/существующей реализации/ и пр факторов


Название: Re: Временно блокировать рисование объекта
Отправлено: Igors от Сентябрь 30, 2010, 13:24
Можно в объекте данных генерировать события:

Код:
Q_SIGNALS:
void updating();   // перед обновлением
void duringUpdate(); // в процессе обновления несколько раз
void updated(); // после обновления
В данном случае объект пассивен, окно знает контейнер объектов которые надо нарисовать

Можно менять долго копию объекта, а в конце по ОК быстро вставить в основную структуру...
Это выглядит хорошо, но обойтись оператором = не удается. Объект зарегистрирован, его удаление вызывает запись undo на диск и.т.п.  А вот "заблокировать" объект достаточно легко.

Код
C++ (Qt)
DisplayData * MyObject::GetDisplayData( void );
 

Все вызывающие проверяют возвращаемое значение на ноль, рисование безопасно. Но ведь "создающие" тоже пользуются тем же GetDisplayData, по сути они его и заряжают.


Название: Re: Временно блокировать рисование объекта
Отправлено: Akon от Сентябрь 30, 2010, 14:11
Обычно, если объектов много (их неэффективно делать QObject'ами), то активен QObject контейнер. В сигналах контейнера будут передаваться объекты. Без сигналов все равно не обойтись.



Название: Re: Временно блокировать рисование объекта
Отправлено: Igors от Сентябрь 30, 2010, 15:06
Обычно, если объектов много (их неэффективно делать QObject'ами), то активен QObject контейнер. В сигналах контейнера будут передаваться объекты. Без сигналов все равно не обойтись.
Не очень понятно кто кому сигналит  :) Если все сводится к ф-ции-члену типа CanBeDrawn (по существу флажок предложенный в #1), то меня это не устраивает, если нужно расскажу почему. Если имеется ввиду что-то другое - поясните.


Название: Re: Временно блокировать рисование объекта
Отправлено: Akon от Сентябрь 30, 2010, 20:28
Окна отображают данные с контейнера. В контейнере что-то изменяется/добавляется/удаляется. Как окна узнают об этом? Посредством подписки на сигналы с контейнера. Короче паттерн "Наблюдатель". Я это имел ввиду.

В твоем случае, поскольку процесс обновления длительный и с Cancel'ом, вместо одного сигнала я предложил три.

Под контейнером я понимаю объект логики, а не что-нибудь примитивное вроде QList.


Название: Re: Временно блокировать рисование объекта
Отправлено: Igors от Сентябрь 30, 2010, 20:43
Окна отображают данные с контейнера. В контейнере что-то изменяется/добавляется/удаляется. Как окна узнают об этом? Посредством подписки на сигналы с контейнера. Короче паттерн "Наблюдатель". Я это имел ввиду.

В твоем случае, поскольку процесс обновления длительный и с Cancel'ом, вместо одного сигнала я предложил три.
Ну эффект 3-х тот же. Окно не может разбираться с каждым объектом индивидуально - нет смысла т.к. объекты могут перекрывать друг друга произвольным образом. Поэтому реально окно рисует все объекты контейнера. И если какой-то объект не готов - рухнет


Название: Re: Временно блокировать рисование объекта
Отправлено: Akon от Сентябрь 30, 2010, 21:08
Объекты обновляются в своем потоке или GUI'шном?


Название: Re: Временно блокировать рисование объекта
Отправлено: Igors от Сентябрь 30, 2010, 21:25
Объекты обновляются в своем потоке или GUI'шном?
Здесь все просто в главной нитке - но это не делает жизнь легче  :)


Название: Re: Временно блокировать рисование объекта
Отправлено: Alex_cs_gsp от Сентябрь 30, 2010, 21:40
Но мне это не очень нравится - придется вставлять эту проверку во все (разнообразные) рисования. Какие есть еще возможности?
Спасибо

А если эти все разнообразные рисования вывести через наследование? - тогда пусть флажок в базовом классе проверяется.
Например
Код:
class CBase
{
    public:
         virtual void SomePrint() = 0;

    private:
         void _DoPrint() {if(flag)this->SomePrint();}
};


class CDerive : public CBase
{
    public:
    void SomePrint();
};

А когда нужна перерисовка, вызывать метод _DoPrint() ? Или как-то так.


Название: Re: Временно блокировать рисование объекта
Отправлено: Igors от Сентябрь 30, 2010, 21:52
А если эти все разнообразные рисования вывести через наследование? - тогда пусть флажок в базовом классе проверяется.
Завести флажок (метод, сигнал) - не вопрос. Проблема в том что проверять его придется из очень многих мест. Во-первых, рисующих окон не одно, и даже не 10 (хотя одновременно открытых обычно немного). Во-вторых, объект может участвовать в рисовании неявно. Пример: должно рисоваться "нечто среднее" между 2-мя объектами (морф). Тогда сами объекты не рисуются, но чтобы получить это среднее - надо иметь DisplayData каждого, т.е. проблема та же. 


Название: Re: Временно блокировать рисование объекта
Отправлено: Alex_cs_gsp от Сентябрь 30, 2010, 21:58
А через фильтр сообщений не получится?


Название: Re: Временно блокировать рисование объекта
Отправлено: Akon от Сентябрь 30, 2010, 22:01
Выведи обработку рисования в кокой-нибудь отдельный класс. Он будет проверять флаги и т.п., а предоставлять максимально удобный интерфейс для отрисовки. Окна будут юзать этот класс.

Приведу пример для предложенного мной решения: допустим, есть окно, отображающее графический файл. Файл загружается по сети долго. Сервер обновляет данный файл. Пользователь нажимает кнопку "обновить". Команда идет в контейнер, тот выбрасывает сигнал updating(). Окно сразу же стирается и пишется "Loading... 0%". Далее по мере загрузки контейнер периодически бросает сигнал duringUpdate(). Соответственно в окне "Loading... 1%" и т.д. Когда файл будет загружен, контейнер бросает сигнал updated(), и окно отображает файл.



Название: Re: Временно блокировать рисование объекта
Отправлено: Igors от Сентябрь 30, 2010, 22:21
А через фильтр сообщений не получится?
Каким образои?

Выведи обработку рисования в кокой-нибудь отдельный класс. Он будет проверять флаги и т.п., а предоставлять максимально удобный интерфейс для отрисовки. Окна будут юзать этот класс.
Базовый класс есть, но "что рисовать" не может быть общим для всех, у каждого окна свой набор объектов (иногда всего 1 объект)

Приведу пример для предложенного мной решения: допустим, есть окно, отображающее графический файл. Файл загружается по сети долго. Сервер обновляет данный файл. Пользователь нажимает кнопку "обновить". Команда идет в контейнер, тот выбрасывает сигнал updating(). Окно сразу же стирается и пишется "Loading... 0%". Далее по мере загрузки контейнер периодически бросает сигнал duringUpdate(). Соответственно в окне "Loading... 1%" и т.д. Когда файл будет загружен, контейнер бросает сигнал updated(), и окно отображает файл.
Ну это ситуация простая - сначала все загрузили - потом все отрисовали. Моя же задача "исключить" из рисования невалидный объект


Название: Re: Временно блокировать рисование объекта
Отправлено: Akon от Сентябрь 30, 2010, 22:38
Есть объект. В плане рисования оъект или готов или не готов. При рисовании если хотя бы один из объектов не готов, то:
1) не рисуется ничего (Loading x%);
2) рисуются только готовые объекты.

Я привел свой вариант на п.1. Если п.2, то мне не понятно в чем проблема - ну исключил неготовые и отрисовал? Или проблема в самом алгоритме исключения?


Название: Re: Временно блокировать рисование объекта
Отправлено: Alex_cs_gsp от Сентябрь 30, 2010, 22:45
А через фильтр сообщений не получится?
Каким образои?

Отлавливать paintEvent() и проверять любимый флаг.


Название: Re: Временно блокировать рисование объекта
Отправлено: Igors от Сентябрь 30, 2010, 22:50
то мне не понятно в чем проблема - ну исключил неготовые и отрисовал? Или проблема в самом алгоритме исключения?
А каким образом "исключил"? См. пост #13 по поводу того какие проблемы я имею

Отлавливать paintEvent() и проверять любимый флаг.
А есть ли еще идеи кроме проверки флажка?


Название: Re: Временно блокировать рисование объекта
Отправлено: Alex_cs_gsp от Сентябрь 30, 2010, 22:53
Так все-равно, если есть что-то "встроенное", то там также флаг проверяется.


Название: Re: Временно блокировать рисование объекта
Отправлено: Akon от Сентябрь 30, 2010, 23:07
Цитировать
А каким образом "исключил"? См. пост #13 по поводу того какие проблемы я имею

Т.е. проблема в механизме исключения? Тогда рисование (PaintEvent'ы и т.п.) это отдельная (тривиальная) задача и пох. сколько там окон.


Название: Re: Временно блокировать рисование объекта
Отправлено: Igors от Сентябрь 30, 2010, 23:35
Т.е. проблема в механизме исключения?
Да. Проверку на созданный флажок придется втыкивать в очень многие места, а если появятся новые - опять тыкать. И нельзя сказать "ну это неизбежно" - ведь способ исключения уже есть (см. пост #5)