在 Windows Vista 和更高版本上,我想要一个带有正常窗口阴影的菜单。所以我必须做两件事:
CS_DROPSHADOW
从菜单HWND
中删除WNDCLASS
Qt 在核心深处添加的内容。
- 使用 DWM API 添加阴影。
诀窍是捕获QEvent::WinIdChange
以获取HWND
菜单窗口的句柄,然后使用GetClassLong
/SetClassLong
删除CS_DROPSHADOW
标志。我只这样做一次(通过使用 a static bool
),因为WNDCLASS
所有菜单的 总是相同的。如果您的应用程序的一部分想要显示菜单阴影而其他部分不想要,这可能会导致问题。
我已经子类化了QMenu
,并且在创建菜单时我总是使用我的覆盖类
Menu * my_menu = new Menu(tr("&File"));
mainMenu->addMenu(my_menu);
这是整个代码,享受:
菜单.h
#ifndef MENU_H
#define MENU_H
#include <QMenu>
class Menu : public QMenu
{
Q_OBJECT
public:
explicit Menu(QWidget *parent = 0);
explicit Menu(const QString & title);
protected:
virtual bool event(QEvent *event);
signals:
public slots:
};
#endif // MENU_H
菜单.cpp
#include "menu.h"
#pragma comment( lib, "dwmapi.lib" )
#include "dwmapi.h"
Menu::Menu(QWidget *parent) :
QMenu(parent)
{
}
Menu::Menu(const QString &title) :
QMenu(title)
{
}
bool Menu::event(QEvent *event)
{
static bool class_amended = false;
if (event->type() == QEvent::WinIdChange)
{
HWND hwnd = reinterpret_cast<HWND>(winId());
if (class_amended == false)
{
class_amended = true;
DWORD class_style = ::GetClassLong(hwnd, GCL_STYLE);
class_style &= ~CS_DROPSHADOW;
::SetClassLong(hwnd, GCL_STYLE, class_style);
}
DWMNCRENDERINGPOLICY val = DWMNCRP_ENABLED;
::DwmSetWindowAttribute(hwnd, DWMWA_NCRENDERING_POLICY, &val, sizeof(DWMNCRENDERINGPOLICY));
// This will turn OFF the shadow
// MARGINS m = {0};
// This will turn ON the shadow
MARGINS m = {-1};
HRESULT hr = ::DwmExtendFrameIntoClientArea(hwnd, &m);
if( SUCCEEDED(hr) )
{
//do more things
}
}
return QWidget::event(event);
}