继承QMenu重写它的paintEvent
代码示例
CustomMenu::CustomMenu(QWidget *parent)
: QMenu(parent)
{
this->setWindowFlag(Qt::FramelessWindowHint);//无边框
this->setWindowFlag(Qt::NoDropShadowWindowHint);//取消windows自带阴影
this->setAttribute(Qt::WA_TranslucentBackground);//透明背景
m_ShadowWidth = 10;//m_ShadowWidth与菜单的margin保持一致
//主要是给menu添加一定的margin用来显示阴影,其余的样式就根据自己的需要来写吧
m_StyleSheet = "QMenu {margin:10px;/*……*/}";
this->setStyleSheet(m_StyleSheet);
}
void CustomMenu::paintEvent(QPaintEvent *e) {
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing, true);
//绘制阴影
painter.drawPixmap(this->rect(), ninePatchScalePixmap(":/Resources/shadow_10px.png", m_ShadowWidth, m_ShadowWidth, this->width(), this->height()+ m_ShadowWidth));//m_ShadowWidth与菜单的margin保持一致
//绘制主体
QMenu::paintEvent(e);
}
QPixmap CDMLCustomMenu::ninePatchScalePixmap(QString picName, int iHorzSplit, int iVertSplit, int DstWidth, int DstHeight)
{
QPixmap* pix = new QPixmap(picName);
int pixWidth = pix->width();
int pixHeight = pix->height();
QPixmap pix_1 = pix->copy(0, 0, iHorzSplit, iVertSplit);
QPixmap pix_2 = pix->copy(iHorzSplit, 0, pixWidth - iHorzSplit * 2, iVertSplit);
QPixmap pix_3 = pix->copy(pixWidth - iHorzSplit, 0, iHorzSplit, iVertSplit);
QPixmap pix_4 = pix->copy(0, iVertSplit, iHorzSplit, pixHeight - iVertSplit * 2);
QPixmap pix_5 = pix->copy(iHorzSplit, iVertSplit, pixWidth - iHorzSplit * 2, pixHeight - iVertSplit * 2);
QPixmap pix_6 = pix->copy(pixWidth - iHorzSplit, iVertSplit, iHorzSplit, pixHeight - iVertSplit * 2);
QPixmap pix_7 = pix->copy(0, pixHeight - iVertSplit, iHorzSplit, iVertSplit);
QPixmap pix_8 = pix->copy(iHorzSplit, pixHeight - iVertSplit, pixWidth - iHorzSplit * 2, pixWidth - iHorzSplit * 2);
QPixmap pix_9 = pix->copy(pixWidth - iHorzSplit, pixHeight - iVertSplit, iHorzSplit, iVertSplit);
pix_2 = pix_2.scaled(DstWidth - iHorzSplit * 2, iVertSplit, Qt::IgnoreAspectRatio);//保持高度拉宽;
pix_4 = pix_4.scaled(iHorzSplit, DstHeight - iVertSplit * 2, Qt::IgnoreAspectRatio);//保持宽度拉高;
pix_5 = pix_5.scaled(DstWidth - iHorzSplit * 2, DstHeight - iVertSplit * 2, Qt::IgnoreAspectRatio);//宽高都缩放;
pix_6 = pix_6.scaled(iHorzSplit, DstHeight - iVertSplit * 2, Qt::IgnoreAspectRatio);//保持宽度拉高;
pix_8 = pix_8.scaled(DstWidth - iHorzSplit * 2, iVertSplit);//保持高度拉宽;
QPixmap resultImg(DstWidth, DstHeight);
// 需设置背景透明;
resultImg.fill(Qt::transparent);
QPainter* painter = new QPainter(&resultImg);
if (!resultImg.isNull()) {
painter->drawPixmap(0, 0, pix_1);
painter->drawPixmap(iHorzSplit, 0, pix_2);
painter->drawPixmap(DstWidth - iHorzSplit, 0, pix_3);
painter->drawPixmap(0, iVertSplit, pix_4);
painter->drawPixmap(iHorzSplit, iVertSplit, pix_5);
painter->drawPixmap(DstWidth - iHorzSplit, iVertSplit, pix_6);
painter->drawPixmap(0, DstHeight - iVertSplit, pix_7);
painter->drawPixmap(iHorzSplit, DstHeight - iVertSplit, pix_8);
painter->drawPixmap(DstWidth - iHorzSplit, DstHeight - iVertSplit, pix_9);
painter->end();
}
return resultImg;
}
其中ninePatchScalePixmap函数来自Qt之使用QPainter自绘实现窗口阴影边框的博客,其中还有其他的阴影实现方式,大家也可以参考一下。
使用的阴影图片如下,它的阴影宽度为10px,对于其他宽度的阴影就不太适用了,需要再制作一张
实现效果
需要注意的是,因为给菜单添加了一定的margin用来显示阴影,所以菜单显示时会向右下角偏移,要记得设置回来。
更多菜单样式的优化