Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Как рисовать на QImage с прозрачностью?
Форум на CrossPlatform.RU > Библиотеки > Qt > Qt Система рисования. Печать
Rocky
Всем привет!
вот тут 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);


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



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

Спасибо!
Litkevich Yuriy
Rocky, а ты про painter.setOpacity не забыл?
Rocky
неа (( в том-то и дело что не забыл
Litkevich Yuriy
Rocky, ты можешь выложить код AeroButton модифицированный под QImage?
Rocky
Вот:
Раскрывающийся текст
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
Rocky, сделал попроще чем у тебя и всё работает (Проверял на виндовозе). Проверь
Нажмите для просмотра прикрепленного файла
П.С. на окно добавил переключатель, чтобы рисовать напрямую или через QImage
Rocky
Странно.. но действительно работает.. ))

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

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



Вобщем щас вот так в линуксе выглядит:

Завтра на работе сделаю скрин как с этим же кодом в XP.

---------------------------------------
Вот так выглядит картинка в винде
Litkevich Yuriy
Цитата(Rocky @ 5.2.2010, 3:50) *
Если в конструкторе класса формировать пусть тот же QImage, то как? В смысле если мы находимся внутри самого конструктора класса, то его объект еще не создан. И тем более не отображен на экране. Как тогда получить правильные размеры всех виджетов и пр?
есть разные способы применительно к твоей задаче:
1) Поискать по форуму по поводу определения размеров в конструкторе (точно помню обсуждалось)
2) Отлавливать resizeEvent и корректировать QImage
3) Сделать как в файле примера %QTDIR%\examples\painting\svgviewer\svgview.cpp класс SvgRasterView
4) переопределить метод show(), в котором вызывать метод базового класса (после него станут известны размеры), а затем корректировать QImage
Rocky
Все понятно.
Litkevich Yuriy
Цитата(Rocky @ 4.2.2010, 22:43) *
Но чтука в том что под виндой эти кнопки получаются с идеально на мой взгляд ровными обводами засчет антиалайзинга.. А вот под линуксом они ужасны.
Посмотри эту тему может в будущем пригодится.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Форум IP.Board © 2001-2024 IPS, Inc.