miguel
miguel

Reputation: 159

Qt menu without shadow?

I copied the question description below from other asked but not answered question, because this is the exactly the same one I wanna ask.

I have a QMenu with a translucent background and rounded edges (border-radius). Unfortunately, Windows 7 draws a drop shadow for this menu, which does not fit to the rounded edges. Its the shadow that would be drawn for normal rectangular menus.

Is there either - a way to completely disable drawing drop shadows for QMenu or - a way to make the shadow fit to the rounded edges ?

Here is a minimalistic example where it occurs:

QPushButton b("press me");
QMenu m;
m.addAction("hello"); m.addAction("world");
m.setWindowFlags(m.windowFlags() | Qt::FramelessWindowHint);
m.setAttribute(Qt::WA_TranslucentBackground);
m.setStyleSheet("background:rgba(255,0,0,50%); border-radius:5px;");
b.setMenu(&m);
b.show();

Right now I have to turn off the menu shadow in Windows Control panel manually to get rid of that shadow. Actually what I want to achieve is a menu like Qt's pie menu or a menu like this one: http://upload.wikimedia.org/wikipedia/commons/8/85/Blender_2.36_Screenshot.jpg I tried the popup widget, but it gets the shadow artifact described above. Could anyone help this out?

Upvotes: 1

Views: 2781

Answers (2)

Martin Cohen
Martin Cohen

Reputation: 161

On Windows Vista and higher, I wanted a menu with normal window shadow. So I had to do two things:

  1. Remove CS_DROPSHADOW from the menu HWND's WNDCLASS that Qt is adding deep down in the core.
  2. Add shadow using DWM APIs.

The trick is to capture QEvent::WinIdChange to get the HWND handle to the menu window, and then to use GetClassLong / SetClassLong to remove CS_DROPSHADOW flag. I'm doing this only once (by using a static bool), as theWNDCLASS is always the same for all menus. This might lead into a problem if part of your app wants to show the menu shadows and other does not.

I have subclassed the QMenu and I'm always using my overriden class when creating menus

Menu * my_menu = new Menu(tr("&File"));
mainMenu->addMenu(my_menu);

Here's the whole code, enjoy:

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

menu.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);
}

Upvotes: 3

miguel
miguel

Reputation: 159

I just remove the Qt::popup flag to get rid of the shadow. And I have to add close codes to any other background UI. These have been more extra work, but I got what I want :)

Upvotes: 0

Related Questions