Версия для печати темы

Нажмите сюда для просмотра этой темы в обычном формате

Форум на CrossPlatform.RU _ Qt Система рисования. Печать _ Как рисовать на QImage с прозрачностью?

Автор: Rocky 4.2.2010, 19:43

Всем привет!
вот тут http://www.forum.crossplatform.ru/index.php?showtopic=4154 Litkevich Yuriy выложил пример AeroButton. В программе сделал кнопки примерно также. Но чтука в том что под виндой эти кнопки получаются с идеально на мой взгляд ровными обводами засчет антиалайзинга.. А вот под линуксом они ужасны. Вычитал, что в иксах нужно для достижения такого же результат включить какую-то опцию отрисовки. Но есть универсальный способ: рисование на QImage (т.е. как бы использование его движка, а не "движка" ОС). Вот делаю как в книге написано =)

void CRoundButton::paintEvent(QPaintEvent *pEvent)
{
    

    QImage oImage(this->size(), QImage::Format_ARGB32_Premultiplied);
    QPainter oImagePainter(&oImage);
    oImagePainter.initFrom(this);
    oImagePainter.setRenderHint(QPainter::Antialiasing, true);
    oImagePainter.eraseRect(this->rect());
//тут отрисовка по сути таже что и в примере aerobutton (только на oImagePainter)
//и потом
    oImagePainter.end();

    QPainter oWidgetPainter(this);
    oWidgetPainter.drawImage(0, 0, oImage);


Кнопки рисуются, причем прозрачные... но вот по краям виден белый прямоугольный фон. Вот пример:

http://www.radikal.ru

Как это можно победить? Пробовал играться с QPainter::CompositionMode, максимально только к этому беломы фону прозрачность добавляется....но сам он не исчезает естественно...

Спасибо!

Автор: Litkevich Yuriy 4.2.2010, 21:15

Rocky, а ты про painter.setOpacity не забыл?

Автор: Rocky 4.2.2010, 21:28

неа (( в том-то и дело что не забыл

Автор: Litkevich Yuriy 4.2.2010, 21:30

Rocky, ты можешь выложить код AeroButton модифицированный под QImage?

Автор: Rocky 4.2.2010, 21:39

Вот:

Раскрывающийся текст
void CRoundButton::paintEvent(QPaintEvent *pEvent)
{
    Q_UNUSED(pEvent);

    QImage oImage(this->size(), QImage::Format_ARGB32_Premultiplied);
    QPainter oImagePainter(&oImage);
    //oImagePainter.setCompositionMode(QPainter::CompositionMode_Xor); //это самое лучшее - белый фон почти невидим, но он есть
    oImagePainter.initFrom(this);
    oImagePainter.setRenderHint(QPainter::Antialiasing, true);
    oImagePainter.eraseRect(this->rect());

    //test for state changes
    QColor button_color;
    if (this->isEnabled())
    {
        m_bHovered ? button_color = m_oHighlight : button_color = m_oColor;
        if (m_bPressed) button_color = m_oPress;
    }
    else
    {
        button_color = QColor(50, 50, 50);
    }

    QRect button_rect = this->geometry();

    //outline
    oImagePainter.setPen(QPen(QBrush(Qt::black), 2.0));
    QPainterPath outline;
    outline.addRoundRect(0, 0, button_rect.width(), button_rect.height(), m_nRoundness, m_nRoundness);
    oImagePainter.setOpacity(m_dOpacity);
    oImagePainter.drawPath(outline);

    //Linear Gradient
    QLinearGradient oLinearGradient(0, 0, 0, button_rect.height());
    oLinearGradient.setSpread(QGradient::ReflectSpread);
    oLinearGradient.setColorAt(0.0, button_color);
    oLinearGradient.setColorAt(0.4, m_oShadow);
    oLinearGradient.setColorAt(0.6, m_oShadow);
    oLinearGradient.setColorAt(1.0, button_color);

    QBrush brush(oLinearGradient);
    oImagePainter.setBrush(brush);
    oImagePainter.setPen(QPen(QBrush(button_color), 2.0));

    //main button
    QPainterPath oImagePainter_path;
    oImagePainter_path.addRoundRect(1, 1, button_rect.width() - 2, button_rect.height() - 2, m_nRoundness, m_nRoundness);
    oImagePainter.setClipPath(oImagePainter_path);

    oImagePainter.setOpacity(m_dOpacity);
    oImagePainter.drawRoundRect(1, 1, button_rect.width() - 2, button_rect.height() - 2, m_nRoundness, m_nRoundness);

    //glass highlight
    oImagePainter.setBrush(QBrush(Qt::white));
    oImagePainter.setPen(QPen(QBrush(Qt::white), 0.01));
    oImagePainter.setOpacity(0.30);
    oImagePainter.drawRect(1, 1, button_rect.width() - 2, (button_rect.height() / 2) - 2);

    //text
    QString sText = this->text();
    if(!sText.isNull())
    {
        QFont font = this->font();
        oImagePainter.setFont(font);
        oImagePainter.setPen(Qt::white);
        oImagePainter.setOpacity(1.0);
        oImagePainter.drawText(0, 0, button_rect.width(), button_rect.height(), Qt::AlignCenter, sText);
    }

    oImagePainter.end();

    QPainter oWidgetPainter(this);
    //oWidgetPainter.setOpacity(m_dOpacity);//без разницы что включен, что нет
    oWidgetPainter.drawImage(0, 0, oImage);

    pEvent->accept();
}

Автор: Litkevich Yuriy 4.2.2010, 23:02

Rocky, сделал попроще чем у тебя и всё работает (Проверял на виндовозе). Проверь
 AeroButton2.zip ( 4.44 килобайт ) : 434

П.С. на окно добавил переключатель, чтобы рисовать напрямую или через QImage

Автор: Rocky 4.2.2010, 23:57

Странно.. но действительно работает.. ))

дело было в fill(...)

=)

Автор: Litkevich Yuriy 5.2.2010, 0:22

Rocky, отпишись, на Линухе использование QImage даёт лучшее сглаживание или нет.
Ну и если будешь продолжать использовать QImage, то лучше рисовать на QImage в отдельном методе, который вызывается в конструкторе и в методах установки свойств. А в обработчике события рисования только выводить уже готовый QImage (QPainter::drawImage()). Так будет быстрее отрисовка происходить

Автор: Rocky 5.2.2010, 0:50

Да, насчет отрисовки завтра переделаю... Весь день буду оптимизацией заниматься... Хотя стоп... Litkevich Yuriy можно задам вопрос, который давно меня мучает... Вроде как он касается этого. Если в конструкторе класса формировать пусть тот же QImage, то как? В смысле если мы находимся внутри самого конструктора класса, то его объект еще не создан. И тем более не отображен на экране. Как тогда получить правильные размеры всех виджетов и пр? Я щас так делаю: просто в main-е после того, как вызвал exec(...) или show(...) главного окна, вызываю некий метод Initialize(...) который по сути далее вызывается иерархически по вссем потомкам главного виджета (окна).. Но как-то не очень нравится этот способ... Может можно как-то лучше?



Вобщем щас вот так в линуксе выглядит:
http://www.radikal.ru
Завтра на работе сделаю скрин как с этим же кодом в XP.

---------------------------------------
Вот так выглядит картинка в винде
http://www.radikal.ru

Автор: Litkevich Yuriy 5.2.2010, 4:30

Цитата(Rocky @ 5.2.2010, 3:50) *
Если в конструкторе класса формировать пусть тот же QImage, то как? В смысле если мы находимся внутри самого конструктора класса, то его объект еще не создан. И тем более не отображен на экране. Как тогда получить правильные размеры всех виджетов и пр?
есть разные способы применительно к твоей задаче:
1) Поискать по форуму по поводу определения размеров в конструкторе (точно помню обсуждалось)
2) Отлавливать resizeEvent и корректировать QImage
3) Сделать как в файле примера %QTDIR%\examples\painting\svgviewer\svgview.cpp класс SvgRasterView
4) переопределить метод show(), в котором вызывать метод базового класса (после него станут известны размеры), а затем корректировать QImage

Автор: Rocky 5.2.2010, 9:01

Все понятно.

Автор: Litkevich Yuriy 5.2.2010, 16:43

Цитата(Rocky @ 4.2.2010, 22:43) *
Но чтука в том что под виндой эти кнопки получаются с идеально на мой взгляд ровными обводами засчет антиалайзинга.. А вот под линуксом они ужасны.
Посмотри http://www.prog.org.ru/index.php?topic=7152.msg35295#msg35295 может в будущем пригодится.

Форум Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)