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

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

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: [РЕШЕНО] Отрисовка части изображения в QPaintEvent при изменении размера окна  (Прочитано 13941 раз)
marbius
Гость
« : Апрель 25, 2010, 10:27 »

Доброго времени суток.

Совершенно случайно наткнулся на такую неприятную (при большом количестве выводимых объектов) "особенность":
при изменении размеров окна, на котором происходит отрисовка через QPaintEvent, paintRect QPaintEvent::rect () ВСЕГДА возвращает координаты верхнего левого угла для перерисовки как (0;0) - т.е. контент перерысовывается полностью.
Возможно ли как-то изменить ситуацию так, чтобы, например, при изменении размера окна по вертикали по rect() возвращалась только недостающая нижняя часть окна, действительно необходимая для "дорисовки"?

Спасибо.
« Последнее редактирование: Апрель 26, 2010, 16:14 от marbius » Записан
alexman
Гость
« Ответ #1 : Апрель 25, 2010, 10:34 »

Используй void QWidget::resizeEvent( QResizeEvent * event ). А в QResizeEvent можно использовать для анализа методы const QSize & oldSize () const, const QSize & size () const.
Записан
alexman
Гость
« Ответ #2 : Апрель 25, 2010, 10:39 »

А const QRect & QPaintEvent::rect () const всегда возвращает всю область?
Записан
marbius
Гость
« Ответ #3 : Апрель 25, 2010, 11:05 »

Используй void QWidget::resizeEvent( QResizeEvent * event ). А в QResizeEvent можно использовать для анализа методы const QSize & oldSize () const, const QSize & size () const.

Как тогда можно убрать из очереди отрисовку всей области, попадающую в QPaintEvent после изменения размеров окна?
Получается, что область перерисовывается трижды: дважды я инициирую дорисовку "справа" и "снизу", а затем идет обычное сообщение опять-таки на обновление всей области. (введение флагов не помогло)

А const QRect & QPaintEvent::rect () const всегда возвращает всю область?

Не совсем понял вопроса. Я писал, что при изменении размеров окна paintRect rect() возвращает всю область, от (0;0) по (width;height).
« Последнее редактирование: Апрель 25, 2010, 15:09 от marbius » Записан
alexman
Гость
« Ответ #4 : Апрель 25, 2010, 11:50 »

Используй void QWidget::resizeEvent( QResizeEvent * event ). А в QResizeEvent можно использовать для анализа методы const QSize & oldSize () const, const QSize & size () const.

Как тогда можно убрать из очереди отрисовку всей области, попадающую в QPaintEvent после изменения размеров окна?
Получается, что область перерисовывается трижды: дважды я инициирую дорисовку "сверху" и "снизу", а затем идет обычное сообщение опять-таки на обновление всей области. (введение флагов не помогло)
void QWidget::paintEvent ( QPaintEvent * event ) тоже переопредели!

А const QRect & QPaintEvent::rect () const всегда возвращает всю область?

Не совсем понял вопроса. Я писал, что при изменении размеров окна paintRect возвращает всю область, от (0;0) по (width;height).
Написано же про rect! Метод paintRect даже не нашел!
Записан
marbius
Гость
« Ответ #5 : Апрель 25, 2010, 12:04 »

Цитировать
void QWidget::paintEvent ( QPaintEvent * event ) тоже переопредели!

Цитировать
Написано же про rect! Метод paintRect даже не нашел!

Извини, но непродуктивный "разговор": кто-то кого-то не понимает, скорее всего, я.

если я "рисую" самостоятельно, то, скорее всего, метод у меня и так переопределен. вопрос в том, что перерисовка при изменении размеров попадает в очередь, и соответственно в обработчик события, помимо моей воли, так сказать из недр qt. Вопрос сейчас в том, как это можно предотвратить. Я подозреваю, что это происходит из-за перерисовки фона, но могу и ошибаться.

А paintRect - это не метод, это просто моя опечатка. Увы, но разговор шел именно про const QRect & QPaintEvent::rect () const и именно этот метод возвращает нули...
Записан
alexman
Гость
« Ответ #6 : Апрель 25, 2010, 12:10 »

Еще можно использовать флаг Qt::WA_OpaquePaintEvent.
Записан
marbius
Гость
« Ответ #7 : Апрель 25, 2010, 12:24 »

Еще можно использовать флаг Qt::WA_OpaquePaintEvent.

Увы, все те же (0;0) только теперь уже без фона Грустный

Скорее всего придется  смириться с медленной отрисовкой.... Но, все же как-то же это должно решаться...

alexman, спасибо за потраченное время.

Вопрос открыт.


Записан
alexman
Гость
« Ответ #8 : Апрель 25, 2010, 13:33 »

1. Хранить текущий rect и предыдущий rect (оба в глобальных координатах).
2. В void QWidget::resizeEvent ( QResizeEvent * event ), void QWidget::moveEvent ( QMoveEvent * event ) rect-ы пересчитываются.
3. В void QWidget::paintEvent ( QPaintEvent * event ) рисовка (по обоим rect-ам можно проанализировать, что перерисовывать).
4. QPoint QWidget::mapToGlobal ( const QPoint & pos ) const - получинение глобальных координат.
Записан
marbius
Гость
« Ответ #9 : Апрель 25, 2010, 13:51 »

1. Хранить текущий rect и предыдущий rect (оба в глобальных координатах).
2. В void QWidget::resizeEvent ( QResizeEvent * event ), void QWidget::moveEvent ( QMoveEvent * event ) rect-ы пересчитываются.
3. В void QWidget::paintEvent ( QPaintEvent * event ) рисовка (по обоим rect-ам можно проанализировать, что перерисовывать).
4. QPoint QWidget::mapToGlobal ( const QPoint & pos ) const - получинение глобальных координат.

Спасибо за ответ, но соль в том, что:
а) если "не извращаться", то потом при выходе из QWidget::resizeEvent, в очереди все мои попытки отрисовать свои прямоугольники "съедаются" глобальной перерисовкой с координатами (0;0; width*height);
б) если "поизвращаться" и ввести разного рода флаги-блокировки, то получается, что контент будет отрисовываться трижды, как я уже писАл, причем самое печальное, что опять-таки последней будет глобальная перерисовка.

Возможный вариант решения, как всегда прост и уже неоднократно описан: использовать QPixmap, и при QWidget::paintEvent выводить только его, а уже при QWidget::resizeEvent расчитывать свои прямоугольники и выводить на QPixmap. Все же думал, что есть более "прямое" решение.
Записан
alexman
Гость
« Ответ #10 : Апрель 25, 2010, 13:56 »

Возможный вариант решения, как всегда прост и уже неоднократно описан: использовать QPixmap, и при QWidget::paintEvent выводить только его, а уже при QWidget::resizeEvent расчитывать свои прямоугольники и выводить на QPixmap. Все же думал, что есть более "прямое" решение.
Да, это быстро работает! Проверенно много раз!
Записан
marbius
Гость
« Ответ #11 : Апрель 25, 2010, 14:07 »

Да, это быстро работает! Проверенно много раз!

Offtopic
Но это лишние затраты памяти. И к тому же насколько я понял, в Qt и так используется буферизация вывода, а так получается, что еще один дополнительный буфер. Вот это меня смущает при использовании QPixmap. Поправьте меня, если я ошибаюсь.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #12 : Апрель 25, 2010, 14:44 »

1) Какую область (region, rectangle) нужно перерисовывать - занимается ОС. Не видно оснований почему при resize нужно "инвалидировать" только часть - в большинстве случаев окно должно быть полностью обновлено если его размер изменился

2) Кто буферирует - дело темное (платформо-зависимое). Напр. на Mac это сам OC

3) QPixmap - верная дорога. Опасения по поводу расходов на буфер беспочвенны. Прикинем: окно 1024 х 1024, расход памяти 4 Мб. Это по нынешним временам не объем. Для сравнения если Вы масштабируете картинку в несколько раз - очень быстро расходы превышают 100 Мб, но я еще не видел попыток сэкономить память на этом  Улыбающийся
Записан
marbius
Гость
« Ответ #13 : Апрель 25, 2010, 15:03 »

... Не видно оснований почему при resize нужно "инвалидировать" только часть - в большинстве случаев окно должно быть полностью обновлено если его размер изменился...

Ну, я могу возразить (опять-таки частный случай): я тяну окошко за нижнюю границу, у меня невалидная только та часть, которая появляется снизу.

Или вот более худший вариант: есть QWidget - главное окно, в котором находится еще один QWidget - мой виджет, допустим размером 100х100 пикселей, причем для главного окна я установил setMinimumSize (200, 200); я меняю размеры главного окна (тяну мышью, например). Зачем мне перерисовывать дочерний виджет каждый раз при изменении размеров главного окна? (возможно, этот вариант больше offtopic и суть другой темы, но все же имеет место быть).

Чтож, QPixmap - все же более верное и быстрое решение, чем копаться в недрах qt.
Принимаю последнее как решение проблемы.

Записан
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #14 : Апрель 26, 2010, 09:54 »

Qt::WA_StaticContents
Записан

Qt 5.11/4.8.7 (X11/Win)
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


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