QDialog с закругленными углами имеет черные углы вместо того, чтобы быть полупрозрачным - PullRequest
0 голосов
/ 28 сентября 2019

Мне нужно создать QDialog с закругленными полупрозрачными углами.Проблема заключается в том, что при этом углы являются полупрозрачными, но каким-то образом заполняются альфа-свойством Window, делающим его черным (что является моим пониманием причины проблемы)

enter image description here

Четко видны закругленные края, но с черным «фоном».Для подтверждения этот диалог является модальным диалогом, запускаемым QThread из QMainWindow. Это не родительское окно .

CSS для QDialog (корневого) компонента:

QDialog {
    background-color: rgba(250, 250, 250, 255);
    border-radius: 30px;
    color: #3C3C3C;
}

с компоновкой компонентов, как показано ниже

enter image description here

Я также добавил эффект тени на QDialog.Это код конструктора для QDialog:

UpdateDialog::UpdateDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::UpdateDialog)
{
    ui->setupUi(this);

    setWindowFlags(Qt::FramelessWindowHint | Qt::Dialog);
    QGraphicsDropShadowEffect* effect = new QGraphicsDropShadowEffect();
    effect->setBlurRadius(5);
    this->setGraphicsEffect(effect);
}

Примечательно, что родительский элемент QMainWindow имеет следующие атрибуты, установленные в его конструкторе

ui->setupUi(this);
statusBar()->hide();
setWindowFlags(Qt::FramelessWindowHint);
setAttribute(Qt::WA_TranslucentBackground, true);

// Set rounded corners style
setStyleSheet("QMainWindow {\n  background-color:rgba(240,240,240,255);\n   border-radius: 30px;\n}\n\nQDialog {\n    border-radius: 30px;\n}");

// Add shadow to main window
QGraphicsDropShadowEffect* effect = new QGraphicsDropShadowEffect(ui->mainWindow);
effect->setBlurRadius(5);
effect->setOffset(4, 4);
this->setGraphicsEffect(effect);

Как мне сделать это QDialog иметь закругленные полупрозрачные углы?

1 Ответ

1 голос
/ 29 сентября 2019

ОБНОВЛЕНИЕ : Вот намного лучшая версия.Неровные углы беспокоили меня, между прочим.Этот выглядит гладким как шелк и может быть стилизован с помощью CSS или C ++.Требуется округление подкласса QWidget (в отличие от первой версии), но оно того стоит.Опять же, я использую QMessageBox в качестве базового виджета для простоты (без макетов и т. Д.), Но он будет работать с любым QWidget (может понадобиться добавленный флаг окна Qt::Dialog).

Реализация окна сообщения:

#include <QtWidgets>

class RoundedMessageBox : public QMessageBox
{
        Q_OBJECT
    public:
        explicit RoundedMessageBox(QWidget *parent = nullptr) :
          QMessageBox(parent)
        {
            // The FramelessWindowHint flag and WA_TranslucentBackground attribute are vital.
            setWindowFlags(windowFlags() | Qt::FramelessWindowHint | Qt::WindowSystemMenuHint);
            setAttribute(Qt::WA_TranslucentBackground);
        }

        qreal radius = 0.0;        // desired radius in absolute pixels
        qreal borderWidth = -1.0;  // -1 : use style hint frame width;  0 : no border;  > 0 : use this width.

    protected:
        void paintEvent(QPaintEvent *) override
        {
            if (!(windowFlags() & Qt::FramelessWindowHint) && !testAttribute(Qt::WA_TranslucentBackground))
                return;  // nothing to do

            QPainter p(this);
            p.setRenderHint(QPainter::Antialiasing);

            // Have style sheet?
            if (testAttribute(Qt::WA_StyleSheetTarget)) {
                // Let QStylesheetStyle have its way with us.
                QStyleOption opt;
                opt.initFrom(this);
                style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
                p.end();
                return;
            }

            // Paint thyself.
            QRectF rect(QPointF(0, 0), size());
            // Check for a border size.
            qreal penWidth = borderWidth;
            if (penWidth < 0.0) {
                QStyleOption opt;
                opt.initFrom(this);
                penWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth, &opt, this);
            }
            // Got pen?
            if (penWidth > 0.0) {
                p.setPen(QPen(palette().brush(foregroundRole()), penWidth));
                // Ensure border fits inside the available space.
                const qreal dlta = penWidth * 0.5;
                rect.adjust(dlta, dlta, -dlta, -dlta);
            }
            else {
                // QPainter comes with a default 1px pen when initialized on a QWidget.
                p.setPen(Qt::NoPen);
            }
            // Set the brush from palette role.
            p.setBrush(palette().brush(backgroundRole()));
            // Got radius?  Otherwise draw a quicker rect.
            if (radius >= 0.0)
                p.drawRoundedRect(rect, radius, radius, Qt::AbsoluteSize);
            else
                p.drawRect(rect);

            // C'est finí
            p.end();
        }
};

Пример использования, показывающий опции стилей CSS и C ++:

int main(int argc, char *argv[])
{
    //QApplication::setStyle("Fusion");
    QApplication app(argc, argv);

    // Dialog setup
    RoundedMessageBox *msgBox = new RoundedMessageBox();
    msgBox->setAttribute(Qt::WA_DeleteOnClose);
    msgBox->setMinimumSize(300, 300);
    msgBox->setWindowTitle("Frameless window test");

    msgBox->setText("<h3>Frameless rounded message box.</h3>");
    msgBox->setInformativeText("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean fermentum erat rhoncus, "
                               "scelerisque eros ac, hendrerit metus. Nunc ac lorem id tortor porttitor mollis. Nunc "
                               "tristique orci vel risus convallis, non hendrerit sapien condimentum. Phasellus lorem tortor, "
                               "mollis luctus efficitur id, consequat eget nulla. Nam ac magna quis elit tristique hendrerit id "
                               "at erat. Integer id tortor elementum, dictum urna sed, tincidunt metus. Proin ultrices tempus "
                               "lacinia. Integer sit amet fringilla nunc.");

    if (1) {
        // Use QSS style
        app.setStyleSheet(QStringLiteral(
            "QDialog { "
                "border-radius: 12px; "
                "border: 3.5px solid; "
                "border-color: qlineargradient(x1: 1, y1: 1, x2: 0, y2: 0, stop: 0 #ffeb7f, stop: 1 #d09d1e); "
                "background: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 1, stop: 0 #ffeb7f, stop: 1 #d09d1e); "
                "color: #003200; "
            "}"
        ));
    }
    else {
        // Use "native" styling
        msgBox->radius = 12.0;
        msgBox->borderWidth = 3.5;

        QLinearGradient bgGrad(0, 0, 1, 1);
        bgGrad.setCoordinateMode(QGradient::ObjectMode);
        bgGrad.setColorAt(0.0, QColor("gold").lighter());
        bgGrad.setColorAt(1.0, QColor("goldenrod").darker(105));
        QLinearGradient fgGrad(bgGrad);
        fgGrad.setStart(bgGrad.finalStop());
        fgGrad.setFinalStop(bgGrad.start());

        QPalette pal;
        pal.setBrush(QPalette::Window, QBrush(bgGrad));
        pal.setBrush(QPalette::Mid, QBrush(fgGrad));
        pal.setBrush(QPalette::WindowText, QColor("darkgreen").darker());
        msgBox->setPalette(pal);

        msgBox->setForegroundRole(QPalette::Mid);     // default is WindowText
        msgBox->setBackgroundRole(QPalette::Window);  // this is actually the default already
    }

    // Drop shadow doesn't work.
    //  QGraphicsDropShadowEffect* effect = new QGraphicsDropShadowEffect();
    //  effect->setBlurRadius(2);
    //  msgBox->setGraphicsEffect(effect);

    msgBox->show();
    return app.exec();
}

enter image description here


ORIGINAL : с использованием универсального QMessageBox и установки на него маски.

Оказалось, я мог бы использовать простой безрамочный диалог для окна сообщения «о» в новом приложении ... такНу вот.Это самый простой метод, который я могу придумать без повторной реализации процесса рисования виджетов (как в примере с часами Qt).Но у этой реализации есть определенные ограничения, и я еще не пробовал ее на Mac.

Кроме того, тень была очень полезна ... хотя на самом деле ее не видно, она отлично справляется со сглаживанием углов.Отличная идея, даже если это не было первоначальным намерением.:)

#include <QtWidgets>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    // Dialog setup. Actually use a QMessageBox for a shorter example.
    QMessageBox *msgBox = new QMessageBox();
    msgBox->setAttribute(Qt::WA_DeleteOnClose);
    msgBox->setMinimumSize(300, 300);
    msgBox->setWindowTitle("Frameless window test");  // might still be visible eg. in a taskbar
    msgBox->setText("<h3>Frameless rounded message box.</h3>");
    msgBox->setInformativeText("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean fermentum erat rhoncus, "
                               "scelerisque eros ac, hendrerit metus. Nunc ac lorem id tortor porttitor mollis. Nunc "
                               "tristique orci vel risus convallis, non hendrerit sapien condimentum. Phasellus lorem tortor, "
                               "mollis luctus efficitur id, consequat eget nulla. Nam ac magna quis elit tristique hendrerit id "
                               "at erat. Integer id tortor elementum, dictum urna sed, tincidunt metus. Proin ultrices tempus "
                               "lacinia. Integer sit amet fringilla nunc.");

    // Here come the styling bits... First need the frameless window flag hint
    msgBox->setWindowFlags(msgBox->windowFlags() | Qt::FramelessWindowHint | Qt::WindowSystemMenuHint);
    // The desired border radius;
    const int radius = 12;
    // Style the box with CSS. Set the border radius here. 
    // The border style helps blend the corners, but could be omitted.
    // The background is optional... could add other styling here too.
    msgBox->setStyleSheet(QString(
        "QDialog { "
            "border-radius: %1px; "
            "border: 2px solid palette(shadow); "
            "background-color: palette(base); "
        "}"
    ).arg(radius));

    // The effect will not be actually visible outside the rounded window,
    // but it does help get rid of the pixelated rounded corners.
    QGraphicsDropShadowEffect* effect = new QGraphicsDropShadowEffect();
    // The color should match the border color set in CSS.
    effect->setColor(QApplication::palette().color(QPalette::Shadow));
    effect->setBlurRadius(5);
    msgBox->setGraphicsEffect(effect);

    // Need to show the box before we can get its proper dimensions.
    msgBox->show();

    // Here we draw the mask to cover the "cut off" corners, otherwise they show through.
    // The mask is sized based on the current window geometry. If the window were resizable (somehow)
    // then the mask would need to be set in resizeEvent().
    const QRect rect(QPoint(0,0), msgBox->geometry().size());
    QBitmap b(rect.size());
    b.fill(QColor(Qt::color0));
    QPainter painter(&b);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.setBrush(Qt::color1);
    // this radius should match the CSS radius
    painter.drawRoundedRect(rect, radius, radius, Qt::AbsoluteSize);
    painter.end();
    msgBox->setMask(b);

    return app.exec();
}

enter image description here

...