ОБНОВЛЕНИЕ : Вот намного лучшая версия.Неровные углы беспокоили меня, между прочим.Этот выглядит гладким как шелк и может быть стилизован с помощью 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();
}
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();
}