qt stylesheet 隐藏_Qt去掉标题栏之后添加边框阴影的解决方案

Qt去掉标题栏之后添加边框阴影的解决方案

发布时间:2018-12-10 20:47,

浏览次数:952

, 标签:

Qt

<>前言

我们经常需要自定义标题栏,那么去掉标题栏是非常有必要。但是去掉标题栏之后边框阴影也会消失,感觉光秃秃的,不太舒服。接下来我们将讨论添加边框阴影的几种解决方案。

<>解决方案

* 如果是Windows平台,那么可以调用Windows相关API。

* 使用Qt的QGraphicsDropShadowEffect类来实现。

* 使用Qt的qDrawBorderPixmap函数来实现。

* 自己构造出边框阴影QImage并绘制(参考为知笔记源码)。

<>源码实现

<>一、调用Windows相关API

我们调用的是dwmapi.dll即Microsoft Desktop Window Manager API(桌面窗口管理器DWM

的公用界面)的动态链接库的相关函数。

#include "WinAPIShadowWidget.h" #include "windwmapi.h" WinAPIShadowWidget::

WinAPIShadowWidget(QWidget *parent) : QWidget(parent) { setWindowFlags(

windowFlags() | Qt::FramelessWindowHint); HWND hwnd = (HWND)this->winId();

DWORD style= ::GetWindowLong(hwnd, GWL_STYLE); //

此行代码可以带回Aero效果,同时也带回了标题栏和边框,在nativeEvent()会再次去掉标题栏 ::SetWindowLong(hwnd,

GWL_STYLE, style | WS_MAXIMIZEBOX | WS_THICKFRAME | WS_CAPTION); //we better

left 1 piexl width of border untouch, so OS can draw nice shadow around it const

MARGINS shadow= { 1, 1, 1, 1 }; WinDwmapi::instance()->

DwmExtendFrameIntoClientArea(HWND(winId()), &shadow); } bool WinAPIShadowWidget

::nativeEvent(const QByteArray &eventType, void *message, long *result) { MSG*

msg= (MSG *)message; switch (msg->message) { case WM_NCCALCSIZE: { // this

kills the window frame and title bar we added with WS_THICKFRAME and WS_CAPTION

*result = 0; return true; } default: return QWidget::nativeEvent(eventType,

message, result); } } ... HRESULT WinDwmapi::DwmExtendFrameIntoClientArea(HWND

hWnd, const MARGINS *pMarInset) const { if (dwm_extendframe_into_client_area_) {

return dwm_extendframe_into_client_area_(hWnd, pMarInset); } return E_NOTIMPL; }

... if (dwmapi_dll_) { dwm_is_composition_enabled_ = \ reinterpret_cast<

DwmIsCompositionEnabledPtr>(GetProcAddress(dwmapi_dll_,

"DwmIsCompositionEnabled")); dwm_extendframe_into_client_area_ = \

reinterpret_cast(GetProcAddress(dwmapi_dll_,

"DwmExtendFrameIntoClientArea")); }

效果图:

<>二、使用Qt的QGraphicsDropShadowEffect类来实现

QGraphicsDropShadowEffect类提供了一个投影效果。可以使用setColor()函数修改投影的颜色。可以使用setOffset()函数修改阴影偏移量,使用setBlurRadius()函数修改阴影的半径。默认情况下,投影是半透明的深灰色(QColor(63,

63, 63, 180)阴影,模糊半径为1,向右下角偏移8个像素。将一个QWidget嵌入到另一个QWidget中,被嵌入的QWidget背景透明。

ShadowEffectWidget::ShadowEffectWidget(QWidget *parent) : QWidget(parent) {

resize(400, 300); setWindowFlags(windowFlags() | Qt::FramelessWindowHint);

setAttribute(Qt::WA_TranslucentBackground); QWidget *pCentralWidget = new

QWidget(this); pCentralWidget->setStyleSheet("background-color: white");

QHBoxLayout*pLayout = new QHBoxLayout(this); pLayout->addWidget(pCentralWidget);

pLayout->setContentsMargins(20, 20, 20, 20); QGraphicsDropShadowEffect *pEffect

= new QGraphicsDropShadowEffect(pCentralWidget); pEffect->setOffset(0, 0);

pEffect->setColor(QColor(QStringLiteral("black"))); pEffect->setBlurRadius(30);

pCentralWidget->setGraphicsEffect(pEffect); }

效果图:

<>三、使用Qt的qDrawBorderPixmap函数来实现

qDrawBorderPixmap函数用于将一个像素图绘制到一个矩形的边缘。使用给定的绘图器将给定的像素映射绘制到给定的目标矩形中。pixmap将被分割成九个部分,并根据边缘结构绘制。需要我们提前做好边框阴影的图片。但是据说这种方式效率并不高,有待考证。

DrawBorderPixmapWidget::DrawBorderPixmapWidget(QWidget *parent) : QWidget(

parent) { resize(800, 600); setWindowFlags(Qt::FramelessWindowHint);

setAttribute(Qt::WA_TranslucentBackground); } void DrawBorderPixmapWidget::

paintEvent(QPaintEvent *e) { Q_UNUSED(e) QPainter painter(this); QPixmap pixmap(

":/client-shadow.png"); qDrawBorderPixmap(&painter, this->rect(), QMargins(8, 8,

8, 8), pixmap); // 绘制中心区域的背景色(不然会是透明的) QRect rect(this->rect().x()+8, this->rect

().y()+8, this->rect().width()-16, this->rect().height()-16); painter.fillRect(

rect, QColor(255, 255, 255)); }

效果图:

<>四、自己构造出边框阴影QImage并绘制

这种方式稍微麻烦点,但是比较灵活,效率也很可观,推荐使用。代码有点多,先上主要的。

inline unsigned char MakeAlpha(int i, double f, int nSize) { if (i == nSize) f

*= 1.2; // double f2 = 1 - cos((double)i / nSize * 3.14 / 2); // return int(fabs

((i * f) * f2)); } QImage MakeShadowImage(int shadowSize, bool activated) { int

size= shadowSize * 2 + 10; QImage image(size, size, QImage::Format_ARGB32);

image.fill(QColor(Qt::black)); // double f = activated ? 4.0 : 1.0; // QSize

szImage= image.size(); // //left for (int y = shadowSize; y < szImage.height() -

shadowSize; y++) { for (int x = 0; x < shadowSize; x++) { int i = x + 1; int

alpha= MakeAlpha(i, f, shadowSize); image.setPixelColor(x, y, QColor(0, 0, 0,

alpha)); } } //right for (int y = shadowSize; y < szImage.height() - shadowSize;

y++) { for (int x = szImage.width() - shadowSize - 1; x < szImage.width(); x++)

{ int i = szImage.width() - x; int alpha = MakeAlpha(i, f, shadowSize); image.

setPixelColor(x, y, QColor(0, 0, 0, alpha)); } } //top for (int y = 0; y <

shadowSize; y++) { int i = y + 1; for (int x = shadowSize; x < szImage.width() -

shadowSize; x++) { int alpha = MakeAlpha(i, f, shadowSize); image.setPixelColor

(x, y, QColor(0, 0, 0, alpha)); } // } //bottom for (int y = szImage.height() -

shadowSize- 1; y < szImage.height(); y++) { int i = szImage.height() - y; for (

int x = shadowSize; x < szImage.width() - shadowSize; x++) { int alpha =

MakeAlpha(i, f, shadowSize); image.setPixelColor(x, y, QColor(0, 0, 0, alpha));

} } // int parentRoundSize = 3; // for (int x = 0; x < shadowSize +

parentRoundSize; x++) { for (int y = 0; y < shadowSize + parentRoundSize; y++) {

int xx = (shadowSize + parentRoundSize) - x; int yy = (shadowSize +

parentRoundSize) - y; int i = int(sqrt(double(xx * xx + yy * yy))); i = std::min

(shadowSize + parentRoundSize, i); i -= parentRoundSize; i = shadowSize - i

; // int alpha = MakeAlpha(i, f, shadowSize); image.setPixelColor(x, y, QColor(0

, 0, 0, alpha)); } } // for (int x = szImage.width() - shadowSize -

parentRoundSize; x < szImage.width(); x++) { for (int y = 0; y < shadowSize +

parentRoundSize; y++) { int xx = (shadowSize + parentRoundSize) - (szImage.width

() - x); int yy = (shadowSize + parentRoundSize) - y; int i = int(sqrt(double(xx

* xx + yy * yy))); i = std::min(shadowSize + parentRoundSize, i); i -=

parentRoundSize; i = shadowSize - i; // int alpha = MakeAlpha(i, f, shadowSize);

image.setPixelColor(x, y, QColor(0, 0, 0, alpha)); } } // for (int x = 0; x <

shadowSize+ parentRoundSize; x++) { for (int y = szImage.height() - shadowSize -

parentRoundSize; y < szImage.height(); y++) { int xx = (shadowSize +

parentRoundSize) - x; int yy = (shadowSize + parentRoundSize) - (szImage.height(

) - y); int i = int(sqrt(double(xx * xx + yy * yy))); i = std::min(

shadowSize+ parentRoundSize, i); i -= parentRoundSize; i = shadowSize - i; //

int alpha = MakeAlpha(i, f, shadowSize); image.setPixelColor(x, y, QColor(0, 0,

0, alpha)); } } // for (int x = szImage.width() - shadowSize - parentRoundSize;

x< szImage.width(); x++) { for (int y = szImage.height() - shadowSize -

parentRoundSize; y < szImage.height(); y++) { int xx = (shadowSize +

parentRoundSize) - (szImage.width() - x); int yy = (shadowSize + parentRoundSize

) - (szImage.height() - y); int i = int(sqrt(double(xx * xx + yy * yy))); i =

std::min(shadowSize + parentRoundSize, i); i -= parentRoundSize; i =

shadowSize- i; // int alpha = MakeAlpha(i, f, shadowSize); image.setPixelColor(x

, y, QColor(0, 0, 0, alpha)); } } // int borderR = 165; int borderG = 165; int

borderB= 165; // if (activated) { borderR = 68; borderG = 138; borderB = 255;

// borderR = 0; // borderG = 0; // borderB = 0; } // int borderSize = 1; //left

for (int i = 0; i < borderSize; i++) { for (int y = shadowSize - 1; y < szImage.

height() - shadowSize + 1; y++) { int x = shadowSize - i - 1; image.

setPixelColor(x, y, QColor(borderR, borderG, borderB, 255)); } } //right for (

int i = 0; i < borderSize; i++) { for (int y = shadowSize - 1; y < szImage.

height() - shadowSize + 1; y++) { int x = szImage.width() - shadowSize - 1 + i +

1; image.setPixelColor(x, y, QColor(borderR, borderG, borderB, 255)); } } //top

for (int i = 0; i < borderSize; i++) { for (int x = shadowSize; x < szImage.

width() - shadowSize; x++) { int y = shadowSize - i - 1; image.setPixelColor(x,

y, QColor(borderR, borderG, borderB, 255)); } } //bottom for (int i = 0; i <

borderSize; i++) { for (int x = shadowSize; x < szImage.width() - shadowSize; x

++) { int y = szImage.height() - shadowSize - 1 + i + 1; image.setPixelColor(x,

y, QColor(borderR, borderG, borderB, 255)); } } // return image; }

调节阴影大小时,只需要调节shadowSize的大小即可。

ShadowWidget::ShadowWidget(int shadowSize, QWidget *parent) : m_shadowSize(

shadowSize) , QWidget(parent) , m_shadow(new Skin9GridImage()) { setAttribute(Qt

::WA_TranslucentBackground); setWindowFlag(Qt::FramelessWindowHint);

setMouseTracking(true); // QImage image = MakeShadowImage(shadowSize, true);

m_shadow->setImage(image, QPoint(shadowSize + 1, shadowSize + 1)); } void

ShadowWidget::paintEvent(QPaintEvent *e) { Q_UNUSED(e) QPainter painter(this);

m_shadow->drawBorder(&painter, rect()); }

效果图:

<>源码下载

CSDN: https://download.csdn.net/download/a844651990/10841366

GitHub: https://github.com/FlyWM/ShadowWidget

你可能感兴趣的:(qt,stylesheet,隐藏)