Russian Qt Forum

Qt => 2D и 3D графика => Тема начата: Alex_C от Апрель 11, 2012, 13:15



Название: Как рисовать на QImage
Отправлено: Alex_C от Апрель 11, 2012, 13:15
Эта тема - в продолжении моей темы
http://www.prog.org.ru/topic_21417_0.html
Собственно есть задача: отрисовка карты местности. На местности каждый объект представляет собой набор точек, которые нужно перевести из точек на местности, в точки на экране. Тут все без проблем. Проблема вот в чем:
если я создаю несколько десятков достаточно сложных QPolygon и затем на событие paintEvent отрисовываю их QPainter.drawPolygon - получается раз 5-10 медленнее, чем когда было на на Дельфи , при рисовании в памяти на Bitmap, а затем отрисовка целикового битмапа куда надо.
Почитав форум, понял что так делать не верно. Рекомендуется отрисовывать все на QImage, и его уже QPainter.drawImage.
Однако вопрос - а как рисовать полигоны, линии и т.п. на QImage - там есть только действия с отдельными точками?
Надеюсь понятно объяснил задачу. :)


Название: Re: Как рисовать на QImage
Отправлено: GreatSnake от Апрель 11, 2012, 13:33
См. базовый класс у QImage.
См. конструктор у QPainter.
Выводы должен сделать сам)


Название: Re: Как рисовать на QImage
Отправлено: Alex_C от Апрель 11, 2012, 15:02
См. базовый класс у QImage.
См. конструктор у QPainter.
Выводы должен сделать сам)

Спасибо! Навело на мысли :)
Хотел бы уточнить вот что: правильно ли я понимаю: QPainter - это то, что в Дельфи называется Canvas? Т.е. получая объект канвас(в Qt пайнтер) рисуем на нем - хоть в памяти в QImage , хоть прямо на виджете?

В таком случае получается правильное решение - создавать QPainter от QImage, рисовать на нем (фактически рисуем то на QImage), и затем выводим этот QImage уже на QPainter нужного нам виджета?


Название: Re: Как рисовать на QImage
Отправлено: Igors от Апрель 11, 2012, 15:37
В таком случае получается правильное решение - создавать QPainter от QImage, рисовать на нем (фактически рисуем то на QImage), и затем выводим этот QImage уже на QPainter нужного нам виджета?
Теоретически да. И вроде бы рисовать на QImage/QPixmap можно в др нитке (или неск нитками)


Название: Re: Как рисовать на QImage
Отправлено: GreatSnake от Апрель 11, 2012, 16:10
И вроде бы рисовать на QImage/QPixmap можно в др нитке (или неск нитками)
на QPixmap навряд-ли, т.к. это ресурс XServer/GDI.


Название: Re: Как рисовать на QImage
Отправлено: Alex_C от Апрель 11, 2012, 16:35
Ок! Спасибо, понятно. Сделал. Появился такой вопрос:
Определил у себя в классе, отвечающим за рисование в конструкторе следующее
Код:
    m_Image = new QImage(m_iWidth, m_iHeight, QImage::Format_RGB32);
    m_Painter = new QPainter(m_Image);
далее в отдельной ф-ции создаю нужный рисунок, и определил ф-цию
Код:
void MapWindow::drawMap(QPainter &p)
{
    p.drawImage(QPoint(0, 0), *m_Image);
}
которая должна вызываться из события paint нужного мне виджета.
В результате у меня рисуется черный квадрат.
До этого когда рисовал на полученном указатете QPainter &p от ф-ции drawMap - все рисовалось нормально.
Чего то еще не учел?


Название: Re: Как рисовать на QImage
Отправлено: Alex_C от Апрель 11, 2012, 16:52
И что уж мне совсем не понятно - если такой кусок кода в ставить в конструктор

Код:
    m_Painter->setPen(QPen(Qt::lightGray,1,Qt::SolidLine));
    m_Painter->setBrush(Qt::blue);
    m_Painter->drawEllipse(QPoint(m_cX, m_cY), m_r, m_r);

То на drawMap(QPainter &p) нарисуется эллипс.
а если так

Код:
void MapWindow::drawMap(QPainter &p)
{
    m_Painter->setPen(QPen(Qt::lightGray,1,Qt::SolidLine));
    m_Painter->setBrush(Qt::blue);
    m_Painter->drawEllipse(QPoint(m_cX, m_cY), m_r, m_r);

    p.drawImage(QPoint(0, 0), *m_Image);
}

ничего... напомню, ф-ция drawMap вызывается на событие пайнт виджета, на котором рисую.
Почему так?


Название: Re: Как рисовать на QImage
Отправлено: GreatSnake от Апрель 11, 2012, 17:02
Код:
void MapWindow::drawMap(QPainter &p)
Как создан p?


Название: Re: Как рисовать на QImage
Отправлено: Igors от Апрель 11, 2012, 17:07
Не делайте m_Painter членом класса, просто объявляйте как локальный перед каждым рисованием QImаge. Ну или вызывайте m_Painter->end() в конце каждого рисования


Название: Re: Как рисовать на QImage
Отправлено: Alex_C от Апрель 11, 2012, 22:03
Код:
void MapWindow::drawMap(QPainter &p)
Как создан p?


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

Код:
void MapPaintWidget::paintEvent(QPaintEvent *)
{
    QPainter p(this);
    CalcWindow(this->parentWidget()).mapWindow->drawMap(p);
}

На такую "странную" конструкцию вызова через предка не обращайте внимание - это я разные способы вызова экспериментирую)))

Не делайте m_Painter членом класса, просто объявляйте как локальный перед каждым рисованием QImаge. Ну или вызывайте m_Painter->end() в конце каждого рисования

Очень интересное замечание! А почему так? Разве не быстрее 1 раз создать, чем каждый раз при перерисовке объекта? Или есть какие то подводные камни?


Название: Re: Как рисовать на QImage
Отправлено: Alex_C от Апрель 12, 2012, 08:38
В общем я тут немного не правильно написал.  ;)
Если делать так:

Код:
void MapWindow::drawMap(QPainter &p)
{
    QPainter p2(m_Image);
    p2.setPen(QPen(Qt::lightGray,1,Qt::SolidLine));
    p2.setBrush(Qt::blue);
    p2.drawEllipse(QPoint(m_cX, m_cY), m_r, m_r);

    p.drawImage(QPoint(0, 0), *m_Image);
}

все рисуется.

я вот если ф-ию drawMap разбить на 2 ф-ции

Код:
void MapWindow::createMap()
{
    QPainter p2(m_Image);
    p2.setPen(QPen(Qt::lightGray,1,Qt::SolidLine));
    p2.setBrush(Qt::blue);
    p2.drawEllipse(QPoint(m_cX, m_cY), m_r, m_r);
}

void MapWindow::drawMap(QPainter &p)
{
    p.drawImage(QPoint(0, 0), *m_Image);
}


и потом пытаться вызывать из paintEvent

Код:
void MapPaintWidget::paintEvent(QPaintEvent *)
{
    QPainter p(this);
    CalcWindow(this->parentWidget()).mapWindow->createMap();
    CalcWindow(this->parentWidget()).mapWindow->drawMap(p);
}

То рисования не происходит.
Понятно что объект QPainter p2 будет только в ф-ции createMap. Но я считал, что он рисует на  m_Image. Или я все не не правильно понимаю объект QPainter?


Название: Re: Как рисовать на QImage
Отправлено: GreatSnake от Апрель 12, 2012, 10:27
Или я все не не правильно понимаю объект QPainter?
Именно.
QPainter-у позволительно рисовать на виджете только в paintEvent() данного виджета.


И перед тем как городить огород всё-таки не мешало почитать описание по QPainter:
Цитата: assistant
Warning: When the paintdevice is a widget, QPainter can only be used inside a paintEvent() function or in a function called by paintEvent(); that is unless the Qt::WA_PaintOutsidePaintEvent widget attribute is set. On Mac OS X and Windows, you can only paint in a paintEvent() function regardless of this attribute's setting.


Название: Re: Как рисовать на QImage
Отправлено: Alex_C от Апрель 12, 2012, 10:40
Да это я знаю... Я просто действительно пытался огород городить ))) Сейчас все заработало.
Одно НО - все равно рисуется конечно существенно медленнее, чем это рисовалось у меня на Дельфи(((


Название: Re: Как рисовать на QImage
Отправлено: GreatSnake от Апрель 12, 2012, 10:46
Одно НО - все равно рисуется конечно существенно медленнее, чем это рисовалось у меня на Дельфи(((
Как минимум одна причина известна изначально - в Qt встроенный double-buffering.
И сглаживание включено?


Название: Re: Как рисовать на QImage
Отправлено: Alex_C от Апрель 12, 2012, 17:21
Как минимум одна причина известна изначально - в Qt встроенный double-buffering.
И сглаживание включено?

Да вроде сейчас во всем разобрался - медленнее конечно, но не так уж сильно как казалось по началу))

Кстати setRenderHint особой разницы не заметил...

Спасибо за советы! Принимаю к сведению!))


Название: Re: Как рисовать на QImage
Отправлено: Alex_C от Апрель 12, 2012, 17:31
А есть ли ф-ция наложения одного QImage на другой по маске?
Т.е. у меня есть QImage, на котором допустим нарисована некая фигура(полигон). Все остальное - черное. Мне нужно эту фигуру наложить на имеющуюся картинку в другом QImage. Раньше я это делал при помощи scineline - в QImage он тоже есть, но может уже что готовое есть?


Название: Re: Как рисовать на QImage
Отправлено: V1KT0P от Апрель 12, 2012, 17:36
А есть ли ф-ция наложения одного QImage на другой по маске?
Т.е. у меня есть QImage, на котором допустим нарисована некая фигура(полигон). Все остальное - черное. Мне нужно эту фигуру наложить на имеющуюся картинку в другом QImage. Раньше я это делал при помощи scineline - в QImage он тоже есть, но может уже что готовое есть?

В примерах к Qt есть пример с разными эффектами наложения изображений. Посмотри, может найдешь нужный.