Qt實現窗口陰影網上有多種實現方式,比如:
1.使用qt自帶的方法,QGraphicsDropShadowEffect
2.通過在無邊框背景透明的窗口中paintevent事件中繪製出來
3.通過dwmapi庫的陰影功能具體代碼如下:
#pragma once
#include <QWidget>
#include "ui_customwidgetframe.h"
class CustomWidgetFrame : public QWidget {
Q_OBJECT
public:
CustomWidgetFrame(QWidget * parent = Q_NULLPTR);
~CustomWidgetFrame();
bool nativeEvent(const QByteArray &eventType, void *message, long *result);
private:
Ui::CustomWidgetFrame ui;
};
#include "customwidgetframe.h"
#include <dwmapi.h>
#include <windowsx.h>
#include <qt_windows.h>
#pragma comment(lib, "dwmapi.lib")
#pragma comment(lib, "user32.lib")
CustomWidgetFrame::CustomWidgetFrame(QWidget * parent) : QWidget(parent) {
ui.setupUi(this);
setWindowFlags(windowFlags() | Qt::FramelessWindowHint);
bool visible = isVisible();
/*
此行代碼可以帶回Aero效果,同時也帶回了標題欄和邊框,在nativeEvent()會再次去掉標題欄
主要的關鍵是WS_THICKFRAME,可以實現窗口停靠邊緣自動改變大小功能和Aero效果
*/
//this line will get titlebar/thick frame/Aero back, which is exactly what we want
//we will get rid of titlebar and thick frame again in nativeEvent() later
HWND hwnd = (HWND)this->winId();
DWORD style = ::GetWindowLong(hwnd, GWL_STYLE);
::SetWindowLong(hwnd, GWL_STYLE, style | WS_THICKFRAME);
//保留一個像素的邊框寬度,否則系統不會繪製邊框陰影
//
//we better left 1 piexl width of border untouch, so OS can draw nice shadow around it
const MARGINS shadow = { 1, 1, 1, 1 };
DwmExtendFrameIntoClientArea(HWND(winId()), &shadow);
}
CustomWidgetFrame::~CustomWidgetFrame() {
}
bool CustomWidgetFrame::nativeEvent(const QByteArray &eventType, void *message, long *result)
{
MSG *param = static_cast<MSG *>(message);
static long cnt = 10000;
printf("######:%x --- %d\n", param->message, ++cnt);
switch (param->message)
{
case WM_NCCALCSIZE: {
/*
此消息用於處理非客戶區域,比如邊框的繪製
返回false,就是按系統的默認處理,如果返回true,而不做任何繪製,則非客戶區域
就不會被繪製,就相當於沒有繪製非客戶區域,所以就會看不到非客戶區域的效果
*/
return true;
}
case WM_NCHITTEST:
{
const LONG border_width = 3;
RECT winrect;
GetWindowRect(HWND(winId()), &winrect);
long x = GET_X_LPARAM(param->lParam);
long y = GET_Y_LPARAM(param->lParam);
/*
只用這種辦法設置動態改變窗口大小比手動通過鼠標事件效果好,可以
避免閃爍問題
*/
//left border
if (x >= winrect.left && x < winrect.left + border_width)
{
*result = HTLEFT;
return true;
}
//right border
if (x < winrect.right && x >= winrect.right - border_width)
{
*result = HTRIGHT;
return true;
}
//bottom border
if (y < winrect.bottom && y >= winrect.bottom - border_width)
{
*result = HTBOTTOM;
return true;
}
//top border
if (y >= winrect.top && y < winrect.top + border_width)
{
*result = HTTOP;
return true;
}
//bottom left corner
if (x >= winrect.left && x < winrect.left + border_width &&
y < winrect.bottom && y >= winrect.bottom - border_width)
{
*result = HTBOTTOMLEFT;
return true;
}
//bottom right corner
if (x < winrect.right && x >= winrect.right - border_width &&
y < winrect.bottom && y >= winrect.bottom - border_width)
{
*result = HTBOTTOMRIGHT;
return true;
}
//top left corner
if (x >= winrect.left && x < winrect.left + border_width &&
y >= winrect.top && y < winrect.top + border_width)
{
*result = HTTOPLEFT;
return true;
}
//top right corner
if (x < winrect.right && x >= winrect.right - border_width &&
y >= winrect.top && y < winrect.top + border_width)
{
*result = HTTOPRIGHT;
return true;
}
return QWidget::nativeEvent(eventType, message, result);
}
}
return QWidget::nativeEvent(eventType, message, result);
}
第3種方法效果還是不錯的,比較推薦使用,效果和系統效果很像
該代碼有2個主要功能:
1.陰影功能
2.拉動窗口改變大小功能,這裏的拉動窗口改變大小功能比較推薦使用,可以避免閃爍問題