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.拉动窗口改变大小功能,这里的拉动窗口改变大小功能比较推荐使用,可以避免闪烁问题